C# 具有ObservableCollection和InotifyProperty更改的WPF MVVM问题
我在添加和删除C# 具有ObservableCollection和InotifyProperty更改的WPF MVVM问题,c#,wpf,mvvm,C#,Wpf,Mvvm,我在添加和删除ObservableCollection的项目时遇到问题。单击绑定按钮后,SQL Server数据库成功更新,但调用方法WorkerInfoCollection.Add和WorkerInfoCollection.RemoveUI未更新。此外,WorkerInfoCollection.Remove(SelectedWorker)根本不删除项。只有在使用LINQ First或Default时,我才能删除此项,但UI中仍然没有任何更改 通过数小时的调试和web搜索,我尝试更改按钮命令参数
ObservableCollection
的项目时遇到问题。单击绑定按钮后,SQL Server数据库成功更新,但调用方法WorkerInfoCollection.Add
和WorkerInfoCollection.Remove
UI未更新。此外,WorkerInfoCollection.Remove(SelectedWorker)
根本不删除项。只有在使用LINQ First或Default时,我才能删除此项,但UI中仍然没有任何更改
通过数小时的调试和web搜索,我尝试更改按钮命令参数:ElementName
和Path
,使用RelativeSource:AncestorType
,在ViewModel构造函数中设置命令值,在setter中设置命令值,在ObservableCollection
中提升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>
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);
}
}
}
}
}
public类WorkerInfoViewModel:ViewModelBase
{
专用SqlDataAdapter数据适配器;
私有数据表;
新工人的私人工人;
所选工人的私人工人;
公共工作者信息新工作者
{
得到
{
if(newWorker==null)
{
return newWorker=new WorkerInfo();
}
否则返回新员工;
}
设置
{
新工人=价值;
}
}
公共工作人员信息选择的工作人员
{
获取{return selectedWorker;}
设置
{
selectedWorker=值;
OnPropertyChanged(“SelectedWorker”);
}
}
私人观察收集工作人员收集;
公共观察收集工作人员收集
{
获取{return workerInfoCollection;}
设置
{
workerInfoCollection=值;
物业变更(“WorkerInfoCollection”);
}
}
公共ICommand AddRecord{get;}
公共ICommand AddRecordImage{get;}
公共ICommand更新记录{get;}
公共ICommand UpdateRecordImage{get;}
私有ICommand deleteCommand;
公共ICommand删除记录
{
得到
{
如果(deleteCommand==null)
{
deleteCommand=new RelayCommand(参数=>
删除记录(单击(参数));
}
返回删除命令;
}
}
public WorkerInfoViewModel()
{
string selectQuery=“从[WorkerInfo]中选择*”;
使用(SqlConnection=new)
SqlConnection(builder.ConnectionString))
{
使用(SqlCommand)命令=新的SqlCommand(selectQuery,
连接)
{
connection.Open();
使用(dataAdapter=newsqldataadapter(命令))
{
dataTable=新的dataTable();
dataAdapter.Fill(dataTable);
WorkerInfoCollection=新
可观察收集();
foreach(dataTable.Rows中的DataRow-DataRow)
{
WorkerInfoCollection.Add
(
新工人信息()
{
WorkerId=
Convert.ToInt32(dataRow[“WorkerId”]),
WorkerHobby=
dataRow[“WorkerHobby”].ToString()
}
);
}
}
connection.Close();
}
}
AddRecord=新的RelayCommand(参数=>
AddRecord_单击(参数));
AddRecordImage=new RelayCommand(参数=>
AddWorkerPhoto_单击(参数));
UpdateRecord=newrelayCommand(参数=>
更新记录(单击(参数));
UpdateRecordImage=new RelayCommand(参数=>
UpdateWorkerPhoto_单击(参数));
//DeleteRecord=新的RelayCommand(参数=>
删除记录(单击(参数));
}
私有void AddRecord\u单击(对象参数)
{
NewWorker=(WorkerInfo)参数;
WorkerInfoCollection.Add
(
新工人信息()
{
WorkerId=NewWorker.WorkerId,
WorkerHobby=NewWorker.WorkerHobby
}
);
string insertQuery=“插入到[WorkerInfo](”+
“沃克里德,”+
“@WorkerHobby”;
使用(SqlConnection=new)
SqlConnection(builder.ConnectionString))
{
connection.Open();
使用(SqlCommand)命令=新的SqlCommand(insertQuery,
连接)
{
尝试
{
command.Parameters.AddWithValue(“@WorkerId”,
NewWorker.WorkerId);
command.Parameters.AddWithValue(“@WorkerHobby”,
新工人;
command.ExecuteNonQuery();
connection.Close();
}
捕获(例外情况除外)
{
MessageBox.Show(“错误”);
日志错误(ex);
}
}
}
}
私有void DeleteRecord_单击(对象参数)
{
SelectedWorker=(WorkerInfo)参数;
string deleteRecord=“从[WorkerInfo]删除”+
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);
}
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string prop = "")
{
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(prop));
}
}
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>