wpf 防止在ItemSource已更改时触发DataGrid的复选框事件

slwdgvem  于 2023-05-30  发布在  其他
关注(0)|答案(1)|浏览(271)

我有一个包含各种单元格的数据网格(一个单元格是复选框)。有一个复选框事件(选中和未选中),我用它来添加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函数做同样的事情。

rjzwgtxy

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”,但这是一个不同的主题,与此无关。

相关问题