提问人:Prouder 提问时间:4/22/2023 最后编辑:Mark RotteveelProuder 更新时间:5/25/2023 访问量:83
防止在更改 itemsource 时触发 datagrid 的复选框事件
Prevent checkbox events of datagrid being triggered when itemsource has been changed
问:
我有一个包含各种单元格的数据网格(一个单元格是一个复选框)。有一个复选框事件(选中和未选中),我用它来向全局余额帐户(文本框)添加 x 金额。数据仅在一年内有效,因此,如果我更改当前年份(通过组合框选择)以评估或检查某些内容,则会更改数据网格的数据源()。ObservableCollection<Member>
我希望当我加载新数据源时,只交换数据网格中的数据。
实际情况是,当我将新数据源(不同的列表)加载到数据网格中时,所有选中和未选中的事件都会被调用,因此会更改文本框的平衡值。
如何防止调用这些事件。是否有类似最后一个事件的东西,我可以用它来设置一个标志(“newSourceInitialized”)来启用检查事件,以便它们仅在用户实际单击它们时才会触发?
WPF 代码位于此处:
<Grid x:Name="MainGrid">
<Grid x:Name="Navbar" Background="#FFADECED" Height="30" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<!--A column for every item in navbar grid must be added here-->
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="Aktuelles Jahr" VerticalAlignment="Center" HorizontalAlignment="left" />
<ComboBox Grid.Column="1" Name="cbxYear" VerticalAlignment="Center" HorizontalAlignment="left" SelectionChanged="cbxYearSelectionChanged" ContextMenuClosing="cbxLostFocus" />
<Button Grid.Column="2" Name="btnAddNewYear" BorderBrush="Transparent" Background="Transparent" VerticalAlignment="Center" HorizontalAlignment="left">
<StackPanel Orientation="Horizontal">
<Image Margin="5,0,0,0" Source="/data/images/add-24-blue.png" Stretch="None"/>
<TextBlock Margin="5,0,10,0" VerticalAlignment="Center"><Run Text="Neues Jahr"/></TextBlock>
</StackPanel>
</Button>
<Button Grid.Column="3" Name="btnSave" Background="Transparent" BorderBrush="Transparent" Click="btnSave_Click" VerticalAlignment="Center" HorizontalAlignment="left">
<DynamicResource ResourceKey="unsaved"/>
</Button>
<TextBox Grid.Column="4" Name="tbxBalance" TextChanged="textBoxNumeric_TextChanged" TextAlignment="Right" TextWrapping="NoWrap" Text="TextBox" VerticalAlignment="Center" HorizontalAlignment="left" Width="151"/>
</Grid>
<Grid x:Name="MainPane">
<!-- loaded event necessary cause otherwise checked events will be triggered -> changing the balance -->
<DataGrid Name="dgMembers" d:ItemsSource="{d:SampleData ItemCount=5}" AutoGenerateColumns="False" Margin="0,27,0,0" Loaded="gridLoaded">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Background" Value="#FF96BFF5"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="BorderThickness" Value="0,0,1,2"/>
<Setter Property="BorderBrush" Value="Black"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Path=id}"/>
<DataGridTextColumn Header="Vorname" Binding="{Binding Path=firstname}"/>
<DataGridTextColumn Header="Nachname" Binding="{Binding Path=lastname}"/>
<DataGridTextColumn Header="Geburtstag" Binding="{Binding Path=birthday, StringFormat={}\{0:dd.MM.yyyy\}}"/>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="cbxPayed" IsChecked="{Binding Path=payed}" Checked="cbxPayedChecked" Unchecked="cbxPayedUnchecked" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Bemerkung" Binding="{Binding Path=note}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Grid>
C# 代码
public partial class MainWindow : Window {
ObservableCollection<Member> lstMembers;
private int MemberDue;
private bool isInitialized = false;
private bool hasChangesToBeSaved = true;//TODO start with false
public MainWindow() {
InitializeComponent();
initializeData();
}
private void btnSave_Click(object sender, RoutedEventArgs e) {
if (hasChangesToBeSaved) { btnSave.Content = FindResource(btnSave.Content == FindResource("unsaved") ? "saved" : "unsaved"); }
saveEverything();
}
private async Task saveEverything() {
await io.saveMembers(lstMembers, "2023");// io is a class for json reading and writing
Properties.Settings.Default.Save();
hasChangesToBeSaved = false;
}
private void initializeData() {
cbxYear.ItemsSource = io.getAllFiles();
cbxYear.SelectedIndex = 0;
loadData();
}
private void loadData() {
lstMembers = io.readMembers(cbxYear.SelectedValue.ToString());
dgMembers.ItemsSource = lstMembers;
MemberDue = Convert.ToInt32(Properties.Settings.Default.MemberDue);
tbxBalance.Text += Properties.Settings.Default.Balance;
isInitialized = true;
}
private void gridLoaded(object sender, EventArgs e) {
isInitialized = true;
}
private void cbxYearSelectionChanged(object sender, EventArgs e) {
if (isInitialized) {
isInitialized = false; // prevent check events being executed while data is loading
loadData();
}
}
private void cbxLostFocus(object sender, EventArgs e) {
isInitialized = true;
}
private void cbxPayedUnchecked(object sender, EventArgs e) {
if (isInitialized) {
string balance = tbxBalance.Text.Equals(String.Empty) ? "0" : tbxBalance.Text;
tbxBalance.Text = (Convert.ToDouble(balance) - MemberDue).ToString();
}
}
private void cbxPayedChecked(object sender, EventArgs e) {
if (isInitialized) {
string balance = tbxBalance.Text.Equals(String.Empty) ? "0" : tbxBalance.Text;
tbxBalance.Text = (Convert.ToDouble(balance) + MemberDue).ToString();
}
}
}
现在,我在启动时阻止检查事件,并使用数据网格的“loaded”事件重新激活它们。这适用于启动。现在,对于用于加载不同年份的数据源更改函数,我想要相同的内容。
答:
解决方案既简单又令人困惑。我在加载新源之前设置了“isInitialized = false”,并在更新源时设置了“isInitialized = true”。
我还更改了“AutoGenerateColumns=”False“并删除了 d:ItemsSource=”{d:SampleData ItemCount=5}”。 这有点帮助:DataGrid 捕获单元格值更改事件,只需单击一下 UpdateSourceTrigger = SourceUpdated
现在,当我加载一个新源时,平衡文本框每次重新加载都会得到另一个“0”,尽管该值实际上是“0”,但这是一个与此无关的不同主题。
评论
isInitialized
false
ItemsSource
loadData