具有ObservableCollection和INotifyPropertyChanged的WPF MVVM问题 - c#

我在添加和删除ObservableCollection的项目时遇到问题。单击绑定的按钮后,SQL Server数据库成功更新,但是在调用方法WorkerInfoCollection.AddWorkerInfoCollection.Remove UI后未更新。而且,WorkerInfoCollection.Remove(SelectedWorker)根本不会删除项目。仅当我使用LINQ First或Default时,我才能删除该项目,但是-UI不变。

通过许多小时的调试和Web搜索,我尝试更改按钮命令参数:ElementNamePath,使用RelativeSource:AncestorType,在ViewModel构造函数中设置Command值,在setter中设置Command值,在OnPropertyChanged使用了不同的绑定模式,在ObservableCollection中添加和删除了项目,甚至尝试重新初始化ObservableCollection并在运行时直接从数据库填充它(有点愚蠢)。没有任何帮助。在网络中搜索也无济于事。

MainWindow.xaml

<Grid>
    <DataGrid Name="WorkerInfoData" 
              HorizontalAlignment="Stretch" 
              Margin="10,10,50,10" 
              VerticalAlignment="Stretch" 
              ItemsSource="{Binding WorkerInfoCollection}"
              SelectedItem="{Binding SelectedWorker,
                                     Mode=TwoWay}">
        <DataGrid.Columns>
            <DataGridTextColumn Header="ID робітника" 
                                Binding="{Binding WorkerId}" />
            <DataGridTemplateColumn Header="Фото"
                                    Width="SizeToCells" 
                                    IsReadOnly="True">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Image Source="{Binding WorkerPhoto}"
                               Height="75"
                               Width="75"
                               Stretch="UniformToFill"
                               RenderOptions.BitmapScalingMode="Fant"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Header="ПІБ" 
                                Binding="{Binding WorkerFullName}" />

            <...>

            <DataGridTextColumn Header="Хоббі" 
                                Binding="{Binding WorkerHobby}" />
        </DataGrid.Columns>
    </DataGrid>
    <StackPanel Panel.ZIndex="3" 
                Name="addRecordPanel" 
                Orientation="Horizontal" 
                HorizontalAlignment="Right" 
                Margin="0,0,-369,0" 
                Width="417"
                DataContext="{Binding NewWorker,
                                      Mode=TwoWay}">
        <Grid>
            <Button Name="buttonHideAddRecordPanel" 
                    Width="48" 
                    Height="48" 
                    Click="ButtonHideAddRecordPanel_Click" 
                    Visibility="Hidden"
                    Margin="0 0 0 100">
                <Button.Background>
                    <SolidColorBrush Color="White"/>
                </Button.Background>
                <Image Source="Images/ClosePanel.png" 
                       RenderOptions.BitmapScalingMode="Fant"/>
            </Button>
            <Button Name="buttonShowAddRecordPanel"
                    Height="48"
                    Width="48" 
                    Click="ButtonShowAddRecordPanel_Click"
                    Margin="0 0 0 100">
                <Button.Background>
                    <SolidColorBrush Color="White"/>
                </Button.Background>
                <Image Source="Images/AddRecord.ico" 
                       RenderOptions.BitmapScalingMode="Fant"/>
            </Button>
        </Grid>
        <Border BorderBrush="DarkGray" 
                BorderThickness="1.5" 
                Width="369" 
                Background="WhiteSmoke" 
                ScrollViewer.VerticalScrollBarVisibility="Disabled">
            <ScrollViewer VerticalScrollBarVisibility="Auto">
                <StackPanel Margin="0 0 0 10"
                            SnapsToDevicePixels="True">
                    <TextBlock Text="Дані нового робітника" 
                               FontSize="16"
                               Background="Gainsboro"
                               TextAlignment="Center"
                               Margin="0"
                               Padding="0 0 0 3"/>
                    <TextBlock Text="ID робітника"
                               Margin="0 10 0 0"/>
                    <TextBox   Text="{Binding WorkerId,

       UpdateSourceTrigger=PropertyChanged}" 
                               Margin="0 5"
                               Width="300"
                               Background="White"/>
                    <TextBlock Text="Фото робітника" 
                               Margin="0 5 0 0"/>
                    <Border BorderBrush="DarkGray"
                            BorderThickness="1"
                            Width="300"
                            Margin="0 5 0 0">
                        <Image Source="{Binding WorkerPhoto, 

         NotifyOnTargetUpdated=True,

         UpdateSourceTrigger=PropertyChanged, 
                                                Mode=TwoWay,
                                                Converter= 
         {conv:ByteToImage}}" 
                               Height="300"
                               Stretch="UniformToFill"/>
                    </Border>
                    <Button Name="AddNewWorkerPhoto" 
                            Width="150" 
                            FontSize="14" 
                            Content="Завантажити фото" 
                            Command="{Binding AddRecordImage}"
                            CommandParameter="{Binding 
         ElementName=addRecordPanel, 

         Path=DataContext}">
                        <Button.DataContext>
                            <VM:WorkerInfoViewModel/>
                        </Button.DataContext>
                    </Button>

                   <...>

                    <Button Name="AddRecord"
                            Content="Додати запис"
                            FontSize="14"
                            Width="150" 
                            Margin="0 10"
                            Command="{Binding AddRecord}"
                            CommandParameter="{Binding 
            ElementName=addRecordPanel, 

            Path=DataContext}">
                        <Button.DataContext>
                            <VM:WorkerInfoViewModel/>
                        </Button.DataContext>
                    </Button>
                </StackPanel>
            </ScrollViewer>
        </Border>
    </StackPanel>
    <StackPanel Panel.ZIndex="3"
                Name="deleteRecordPanel"
                Orientation="Horizontal" 
                HorizontalAlignment="Right" 
                Margin="0,0,-369,0" 
                Width="417">
        <Grid>
            <Button Name="DeleteRecord"
                    Height="48"
                    Width="48" 
                    Margin="0 100 0 0"
                    Command="{Binding DeleteRecord}"
                    CommandParameter="{Binding 
                ElementName=WorkerInfoData, 
                                               Path=SelectedItem}">
                <Button.DataContext>
                    <VM:WorkerInfoViewModel/>
                </Button.DataContext>
                <Button.Background>
                    <SolidColorBrush Color="White"/>
                </Button.Background>
                <Image Source="Images/DeleteRecord.png" 
                       RenderOptions.BitmapScalingMode="Fant"/>
            </Button>
        </Grid>
    </StackPanel>
</Grid>

WorkerInfo.cs

      public class WorkerInfo : INotifyPropertyChanged
      {
             private int workerId;
      <...>
      public int WorkerId
      {
        get { return workerId; }
        set
        {
            workerId = value;
            OnPropertyChanged(nameof(WorkerId));
        }

      <...>

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName]string prop = "")
    {
        PropertyChanged?.Invoke(this, new 
        PropertyChangedEventArgs(prop));
    }

RelayCommand.cs

public class RelayCommand : ICommand
{
    private Action<object> execute;
    private Func<object, bool> canExecute;

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public RelayCommand(Action<object> execute, Func<object, bool> 
    canExecute = null)
    {
        this.execute = execute;
        this.canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return canExecute == null || canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        execute(parameter);
    }
   }

ViewModelBase.cs

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName]string prop = "")
    {
        PropertyChanged?.Invoke(this, new 
  PropertyChangedEventArgs(prop));
    }
}

WorkerInfoViewModel.cs

 public class WorkerInfoViewModel : ViewModelBase
 {
    private SqlDataAdapter dataAdapter;
    private DataTable dataTable;
    private WorkerInfo newWorker;
    private WorkerInfo selectedWorker;

    public WorkerInfo NewWorker
    {
        get
        {
            if (newWorker == null)
            {
                return newWorker = new WorkerInfo();
            }
            else return newWorker;
        }
        set
        {
            newWorker = value;
        }
    }
    public WorkerInfo SelectedWorker
    {
        get { return selectedWorker; }
        set
        {
            selectedWorker = value;
            OnPropertyChanged("SelectedWorker");
        }
    }

    private ObservableCollection<WorkerInfo> workerInfoCollection;
    public ObservableCollection<WorkerInfo> WorkerInfoCollection
    {
        get { return workerInfoCollection; }
        set
        {
            workerInfoCollection = value;
            OnPropertyChanged("WorkerInfoCollection");
        }

    }

    public ICommand AddRecord { get; }
    public ICommand AddRecordImage { get; }
    public ICommand UpdateRecord { get; }
    public ICommand UpdateRecordImage { get; }

    private ICommand deleteCommand;
    public ICommand DeleteRecord
    {
        get
        {
            if (deleteCommand == null)
            {
                deleteCommand = new RelayCommand(parameter => 
        DeleteRecord_Click(parameter));
            }
            return deleteCommand;
        }
    }


    public WorkerInfoViewModel()
    {
        string selectQuery = "SELECT * FROM [WorkerInfo]";

        using (SqlConnection connection = new 
             SqlConnection(builder.ConnectionString))
        {
            using (SqlCommand command = new SqlCommand(selectQuery, 
            connection))
            {
                connection.Open();

                using (dataAdapter = new SqlDataAdapter(command))
                {
                    dataTable = new DataTable();
                    dataAdapter.Fill(dataTable);

                    WorkerInfoCollection = new 
              ObservableCollection<WorkerInfo>();
                    foreach (DataRow dataRow in dataTable.Rows)
                    {
                        WorkerInfoCollection.Add
                            (
                               new WorkerInfo()
                               {
                                   WorkerId = 
                 Convert.ToInt32(dataRow["WorkerId"]),

                 <...>
                                   WorkerHobby = 
                dataRow["WorkerHobby"].ToString()
                               }
                            );
                    }
                }

                connection.Close();
            }
        }

        AddRecord = new RelayCommand(parameter => 
             AddRecord_Click(parameter));
        AddRecordImage = new RelayCommand(parameter => 
                  AddWorkerPhoto_Click(parameter));

        UpdateRecord = new RelayCommand(parameter => 
                   UpdateRecord_Click(parameter));
        UpdateRecordImage = new RelayCommand(parameter => 
             UpdateWorkerPhoto_Click(parameter));

        //DeleteRecord = new RelayCommand(parameter => 
                DeleteRecord_Click(parameter));
    }


    private void AddRecord_Click(object parameter)
    {
        NewWorker = (WorkerInfo)parameter;

        WorkerInfoCollection.Add
            (
                new WorkerInfo()
                {
                    WorkerId = NewWorker.WorkerId,
                    <...>
                    WorkerHobby = NewWorker.WorkerHobby
                }
            );


        string insertQuery = "INSERT INTO [WorkerInfo] (" +
                "WorkerId, " +
                    <...>
                "@WorkerHobby)";

        using (SqlConnection connection = new 
            SqlConnection(builder.ConnectionString))
        {
            connection.Open();

            using (SqlCommand command = new SqlCommand(insertQuery, 
               connection))
            {
                try
                {

                    command.Parameters.AddWithValue("@WorkerId", 
                NewWorker.WorkerId);

                    <...>

                    command.Parameters.AddWithValue("@WorkerHobby", 
              NewWorker.WorkerHobby);

                    command.ExecuteNonQuery();

                    connection.Close();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("error");

                    log.Error(ex);
                }
            }
        }
    }

    private void DeleteRecord_Click(object parameter)
    {
        SelectedWorker = (WorkerInfo)parameter;

        string deleteRecord = "DELETE FROM [WorkerInfo] " +
                              "WHERE WorkerId = @WorkerId";

        if (SelectedWorker != null)
        {
            using (SqlConnection connection = new 
           SqlConnection(builder.ConnectionString))
            {
                connection.Open();

                using (SqlCommand command = new SqlCommand(deleteRecord, 
               connection))
                {
                    try
                    {
                        command.Parameters.AddWithValue("@WorkerId", 
              SelectedWorker.WorkerId);

                        command.ExecuteNonQuery();

                        connection.Close();

                        WorkerInfoCollection.Remove(SelectedWorker);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("error");

                        log.Error(ex);
                    }
                }
            }
        }
    }

参考方案

当您这样做时:

          <Button.DataContext>
                <VM:WorkerInfoViewModel/>
            </Button.DataContext>

实例化workerinfo视图模型的另一个实例。

删除那个。

您想要在相同的viewmodel实例中的相同的observablecollection中添加和删除数据网格的itemssource绑定到该对象。

实际上,您至少有3个该视图模型的实例。

确保只有视图模型的一个实例,这是mainwindow的数据上下文,因此是按钮和datagrid。

Div单击与单选按钮相同吗? - php

有没有一种方法可以使div上的click事件与表单环境中的单选按钮相同?我只希望下面的div提交值,单选按钮很丑代码输出如下:<input id="radio-2011-06-08" value="2011-06-08" type="radio" name="radio_date&#…

故障排除“警告:session_start():无法发送会话高速缓存限制器-标头已发送” - php

我收到警告:session_start()[function.session-start]:无法发送会话缓存限制器-标头已发送(错误输出开始如果我将表单数据提交到其他文件进行处理,则可以正常工作。但是,如果我将表单数据提交到同一页面,则会出现此错误。请建议<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0…

CodeIgniter更新查询被执行两次 - php

我正在使用CodeIgniter 2.2。每次访问页面时,我都必须用+1更新数据库。代码可以工作,但是每次都会增加+2。示例:如果是total views=2,则在单击页面后total views应该是3,但是数据库中的值是4。我确定我在控制器中仅调用一次模型add_one_to_view_image。控制者 function view(){ $view_i…

jQuery Ajax文件上传在客户端浏览器上无法正常工作 - javascript

我正在尝试使用Ajax和JQuery实现个人资料图片上传功能我能够将个人资料图片成功上传到我尝试过的所有机器和移动设备上的数据库中。它适用于我在Chrome,Edge,Firefox,Safari甚至Vivaldi上使用。问题是我住在加拿大的客户无法将他们的个人资料图片上传到数据库。另外,纵向宽高比的图像倾向于向侧面旋转。我一直在要求他重​​新注册并多次提供…

将python scikit学习模型导出到pmml - python

我想将python scikit-learn模型导出到PMML。哪个python软件包最合适?我阅读了有关Augustus的内容,但是我无法使用scikit-learn模型找到任何示例。 python大神给出的解决方案 SkLearn2PMML是 JPMML-SkLearn命令行应用程序周围的薄包装。有关受支持的Scikit-Learn Estimator和…