我有一个包含各种单元格的数据网格(一个单元格是复选框)。有一个复选框事件(选中和未选中),我用它来添加x金额到全局余额帐户(文本框)。数据仅在一年内有效,因此如果我更改当前年份(通过组合框选择)以评估或检查某些内容,我会更改数据网格的数据源(ObservableCollection<Member>
)。
我希望当我加载一个新的数据源时,只有数据网格中的数据被交换。
实际发生的是,当我加载一个新的数据源(不同的列表)到数据网格中时,所有的checked和unchecked事件都被调用,因此改变了文本框的balance值。
我如何防止这些事件被调用。有没有类似最后一个事件的东西,我可以用它来设置一个标志(“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”事件重新激活它们。这对启动是有效的。现在,我想对用于加载不同年份的datasource changed函数做同样的事情。
1条答案
按热度按时间rjzwgtxy1#
解决办法很简单,就是让人摸不着头脑。我在加载一个新的源之前设置“isInitialized = false”,在更新源时设置“isInitialized = true”。
我还更改了“AutoGenerateColumns=“False”并删除了d:ItemsSource="{d:SampleData ItemCount=5}"。这有点帮助:DataGrid catch cell value changed event with a single click on UpdateSourceTrigger = SourceUpdated
现在,当我加载一个新的源时,每次重新加载时,平衡文本框都会得到另一个“0”,尽管值实际上是“0”,但这是一个不同的主题,与此无关。