我在添加和删除ObservableCollection
的项目时遇到问题。单击绑定的按钮后,SQL Server数据库成功更新,但是调用方法WorkerInfoCollection.Add
和WorkerInfoCollection.Remove
之后,UI并未更新。此外,WorkerInfoCollection.Remove(SelectedWorker)
根本不会删除项目。仅当我使用LINQ First或Default时,我才能删除此项目,但是-UI不变。
经过许多小时的调试和网络搜索,我尝试更改按钮命令参数:ElementName
和Path
,使用RelativeSource:AncestorType
,在ViewModel构造函数中设置Command值,设置Command设置器中的值,在OnPropertyChanged
中提高ObservableCollection
,使用不同的绑定模式,从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);
}
}
}
}
}
答案 0 :(得分:5)
当您这样做:
<Button.DataContext>
<VM:WorkerInfoViewModel/>
</Button.DataContext>
这将实例化workerinfo视图模型的另一个实例。
删除。
您想在同一viewmodel实例中的同一observablecollection中添加和删除其数据网格的itemsource。
实际上,您至少有3个该视图模型的实例。
确保您只有一个ViewModel实例,那是mainwindow的数据上下文,因此是按钮和datagrid。