WPF:ValidationRule已触发,但当DataGridComboBox SelectedValueBinding更改时IsDirty == false

问题描述 投票:0回答:1

我的XAML显示与配置为ObservableCollectionRowValidationRule绑定的DataGrid。每当DataGridTextColumn中的值更改时,都会触发ValidationRule并触发IsDirty == true。但是,对于DataGridComboBoxColumn,即使实际上已更新IsDirty == false属性,也会触发ValidationRule,但会触发SelectedValueBinding。我不明白为什么或应该为DataGridComboBoxColumn条目正确执行IsDirty == true而应该做些什么。

UPDATE

我在所有ValidationSteps中运行了ValidationRule,发现收款人ComboBox的值在ValidationStep.RawProposedValue中为已经更改。这与直到ValidationStep.UpdatedValue才显示更改的所有其他列不同。直到ValidationStep.UpdatedValue都不会更改Status ComboBox(可用于枚举),但第一步已存在Payees值。也许它假设ComboBox本身应该已经验证过了?

XAML

<Window.Resources>
    <ObjectDataProvider x:Key="statusEnum" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="data:TransactionStatus" />
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
    <CollectionViewSource x:Key="PayeesView" Source="{Binding Payees}" />
    <convert:BankTransactionConverter x:Key="TransConverter" />
</Window.Resources>
<Grid>
    ...
    <DataGrid x:Name="BankDataGrid" Grid.Row="2"
            ItemsSource="{Binding BankTransactions}"
            SelectedItem="{Binding SelectedBankTransaction, Converter={StaticResource TransConverter}}"
        <DataGrid.RowValidationRules>
            <valid:BankTransactionValidationRule ValidationStep="UpdatedValue"/>
        </DataGrid.RowValidationRules>
            <DataGrid.Columns>
                <DataGridTextColumn x:Name="BankTransReference" Header="Ref" Width="70"
                                    Binding="{Binding Reference}" />
                <DataGridTemplateColumn x:Name="BankTransDate" Header="Date" Width="100" SortMemberPath="Date" >
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Date, StringFormat=\{0:MM/dd/yyyy\}}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding Date}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>

                <DataGridComboBoxColumn x:Name="BankTransPayee" Header="Payee"
                        ItemsSource="{Binding Source={StaticResource PayeesView}}" DisplayMemberPath="Name" 
                        SelectedValueBinding="{Binding PayeeName, UpdateSourceTrigger=LostFocus}" SelectedValuePath="Name" >
                    <DataGridComboBoxColumn.EditingElementStyle>
                        <Style TargetType="ComboBox">
                            <Setter Property="IsEditable" Value="True" />
                        </Style>
                    </DataGridComboBoxColumn.EditingElementStyle>
                </DataGridComboBoxColumn>

                <DataGridTextColumn x:Name="BankTransAmount" Header="Amount" IsReadOnly="True" Width="100" 
                                    Binding="{Binding Amount, StringFormat=\{0:N2\}}" >
                    <DataGridTextColumn.CellStyle>
                        <Style>
                            <Setter Property="TextBlock.TextAlignment" Value="Right" />
                        </Style>
                    </DataGridTextColumn.CellStyle>
                </DataGridTextColumn>

                <DataGridComboBoxColumn x:Name="BankTransStatus" Header="?" Width="18" 
                                        ItemsSource="{Binding Source={StaticResource statusEnum}, Mode=OneWay}" 
                                        SelectedItemBinding="{Binding Status}" />

                <DataGridTextColumn x:Name="BankTransMemo" Header="Memo" Width="220" 
                                    Binding="{Binding Memo}" />
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Click="Button_ShowHideSub">Subs</Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
    </DataGrid>
</Grid>

ValidationRule

public class BankTransactionValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        var bg = (BindingGroup)value;
        var row = (DataGridRow)bg.Owner;
        var item = (BankTransaction)row.Item;

        switch (ValidationStep)
        {
            case ValidationStep.RawProposedValue:
                System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: ValidationStep={ValidationStep.RawProposedValue}");
                ShowInfo(item);
                break;
            case ValidationStep.ConvertedProposedValue:
                System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: ValidationStep={ValidationStep.ConvertedProposedValue}");
                ShowInfo(item);
                break;
            case ValidationStep.UpdatedValue:
                System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: ValidationStep={ValidationStep.UpdatedValue}");
                ShowInfo(item);
                break;
            case ValidationStep.CommittedValue:
                System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: ValidationStep={ValidationStep.CommittedValue}");
                ShowInfo(item);
                break;
            default:    // Should not get here
                System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: DEFAULT\n");
                break;
        }

        if (bg.IsDirty)
        {
            System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: {item.TransactionId} is dirty\n");
        }
        else
        {
            System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: {item.TransactionId} is NOT dirty\n");
        }

        return ValidationResult.ValidResult;
    }

    private void ShowInfo(BankTransaction trans)
    {
        System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: Reference={trans.Reference}");
        System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: Date={trans.Date}");
        System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: PayeeName={trans.PayeeName}");
        System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: Status={trans.Status}");
        System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: Memo={trans.Memo}");
    }
}

输出

BankTransactionTestValidationRule: ValidationStep=RawProposedValue
>> BankTransactionTestValidationRule: Reference=
BankTransactionTestValidationRule: Date=12/24/2019 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=Amazon
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=ConvertedProposedValue
>> BankTransactionTestValidationRule: Reference=
BankTransactionTestValidationRule: Date=12/24/2019 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=Amazon
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=UpdatedValue
>> BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=12/24/2019 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=Amazon
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=CommittedValue
>> BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=12/24/2019 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=Amazon
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=RawProposedValue
BankTransactionTestValidationRule: Reference=2nd row
>> BankTransactionTestValidationRule: Date=12/24/2019 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=Amazon
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=ConvertedProposedValue
BankTransactionTestValidationRule: Reference=2nd row
>> BankTransactionTestValidationRule: Date=12/24/2019 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=Amazon
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=UpdatedValue
BankTransactionTestValidationRule: Reference=2nd row
>> BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=Amazon
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=CommittedValue
BankTransactionTestValidationRule: Reference=2nd row
>> BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=Amazon
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=RawProposedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
>> BankTransactionTestValidationRule: PayeeName=PenFed
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is NOT dirty

BankTransactionTestValidationRule: ValidationStep=ConvertedProposedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
>> BankTransactionTestValidationRule: PayeeName=PenFed
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is NOT dirty

BankTransactionTestValidationRule: ValidationStep=UpdatedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
>> BankTransactionTestValidationRule: PayeeName=PenFed
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is NOT dirty

BankTransactionTestValidationRule: ValidationStep=CommittedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
>> BankTransactionTestValidationRule: PayeeName=PenFed
BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is NOT dirty

BankTransactionTestValidationRule: ValidationStep=RawProposedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=PenFed
>> BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=ConvertedProposedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=PenFed
>> BankTransactionTestValidationRule: Status=N
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=UpdatedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=PenFed
>> BankTransactionTestValidationRule: Status=V
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is NOT dirty

BankTransactionTestValidationRule: ValidationStep=CommittedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=PenFed
>> BankTransactionTestValidationRule: Status=V
BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is NOT dirty

BankTransactionTestValidationRule: ValidationStep=RawProposedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=PenFed
BankTransactionTestValidationRule: Status=V
>> BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=ConvertedProposedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=PenFed
BankTransactionTestValidationRule: Status=V
>> BankTransactionTestValidationRule: Memo=
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=UpdatedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=PenFed
BankTransactionTestValidationRule: Status=V
>> BankTransactionTestValidationRule: Memo=give me some memo
BankTransactionTestValidationRule: 2 is dirty

BankTransactionTestValidationRule: ValidationStep=CommittedValue
BankTransactionTestValidationRule: Reference=2nd row
BankTransactionTestValidationRule: Date=10/6/2020 12:00:00 AM
BankTransactionTestValidationRule: PayeeName=PenFed
BankTransactionTestValidationRule: Status=V
>> BankTransactionTestValidationRule: Memo=give me some memo
BankTransactionTestValidationRule: 2 is dirty
c# wpf validation datagrid
1个回答
0
投票

[我将其发布为答案只是因为它提供了所需的行为。但是,我仍然希望其他人有正确的答案。]

我最终在DataGrid中添加了一个隐藏列,该隐藏列绑定到HiddenPayee的行视图模型中的新属性ItemSource。通过将其设置为等于ValidationRule,可以在PayeeName中更新此[属性。我还添加了一个IsDirty属性(带有私有集),当它们更改except绑定到truePayeeName属性时,该属性由所有其他属性设置为DataGridComboBox。见下文...

XAML更改

<DataGrid.RowValidationRules> <valid:BankTransactionValidationRule ValidationStep="UpdatedValue" /> </DataGrid.RowValidationRules> <DataGrid.Columns> ... <DataGridComboBoxColumn x:Name="BankTransPayee" Header="Payee" ItemsSource="{Binding Source={StaticResource PayeesView}}" DisplayMemberPath="Name" SelectedValueBinding="{Binding PayeeName}" SelectedValuePath="Name" > <DataGridComboBoxColumn.EditingElementStyle> <Style TargetType="ComboBox"> <Setter Property="IsEditable" Value="True" /> </Style> </DataGridComboBoxColumn.EditingElementStyle> </DataGridComboBoxColumn> <DataGridTextColumn x:Name="BankTransHiddenPayee" Binding="{Binding HiddenPayee}" Visibility="Hidden" /> ... </DataGrid.Columns>

银行交易更改

public class BankTransaction : INotifyPropertyChanged, ICloneable { private bool loading = false; // Default constructor is required by DataGrid in order to add new empty row public BankTransaction() { IsDirty = false; Subtransactions.CollectionChanged += Subtransactions_CollectionChanged; } public BankTransaction(int accountId, int transactionId, DateTime date, string memo, TransactionStatus status, string payee, string reference) : this() { loading = true; // For reading from the database AccountId = accountId; TransactionId = transactionId; Date = date; Memo = memo; Status = status; PayeeName = payee; HiddenPayee = payee; Reference = reference; loading = false; } public bool IsDirty { get; private set; } private string hiddenPayee; public string HiddenPayee { get => hiddenPayee; set { if (hiddenPayee != value) { hiddenPayee = value; NotifyPropertyChanged(); IsDirty = !loading; } } } private string payeeName = ""; public string PayeeName { get => payeeName; set { payeeName = value; NotifyPropertyChanged(); // Don't set IsDirty here, it is handled // in HiddenPayee } } private string reference = ""; public string Reference { get => reference; set { reference = value; NotifyPropertyChanged(); IsDirty = !loading; } } ... }

ValidationRule更改

public class BankTransactionValidationRule : ValidationRule { public override ValidationResult Validate(object value, CultureInfo cultureInfo) { var bg = (BindingGroup)value; var row = (DataGridRow)bg.Owner; var item = (BankTransaction)row.Item; // This, because a change in the DataGridComboBoxColumn immediately changes the value // and it does not set bg.IsDirty. So, forced to manually handle this in the item item.HiddenPayee = item.PayeeName; if (item.IsDirty) { System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionValidationRule)}: {item.TransactionId} is dirty"); if (row.IsNewItem) { item.Insert(); } else { item.Update(); } } else { System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionValidationRule)}: {item.TransactionId} is NOT dirty"); } return ValidationResult.ValidResult; } }

© www.soinside.com 2019 - 2024. All rights reserved.