WPF:ValidationRule已激发,但当DataGridComboBoxSelectedValueBinding



My XAML显示绑定到配置了RowValidationRuleObservableCollection的DataGrid。每当DataGridTextColumn中的值发生更改时,就会触发ValidationRule并触发IsDirty == true。然而,对于DataGridComboBoxColumn,ValidationRule被激发,但IsDirty == false,即使SelectedValueBinding属性实际上已经更新。我不明白为什么或者我应该为DataGridComboBoxColumn条目做些什么来正确地导致IsDirty == true

更新

我发现,通过在所有ValidationSteps中运行ValidationRule,收款人组合框的值已经在ValidationStep.RawProposedValue中发生了更改。这与ValidationStep.UpdatedValue之前不会出现更改的所有其他列不同。即使是状态组合框(在枚举中起作用(在ValidationStep.UpdatedValue之前也不会更改,但在第一步时,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>

验证规则

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)}: DEFAULTn");
break;
}
if (bg.IsDirty)
{
System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: {item.TransactionId} is dirtyn");
}
else
{
System.Diagnostics.Debug.WriteLine($"{nameof(BankTransactionTestValidationRule)}: {item.TransactionId} is NOT dirtyn");
}
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

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

我最终向DataGrid添加了一个隐藏列,该列绑定到ItemSource的行视图模型中的新属性HiddenPayee。此属性通过将其设置为PayeeNameValidationRule中更新。我还添加了一个IsDirty属性(带有一个私有集(,当所有其他属性更改时,该属性由true设置,绑定到DataGridComboBoxPayeeName属性除外。请参阅以下内容。。。

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;
}
}
...
}

验证规则更改

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;
// A change in a DataGridComboBoxColumn immediately changes the value of the SelectedValue (even at RawProposedValue)
// so use hidden properties that are set here and evaluated in the view model class to set its IsDirty property.
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;
}
}

相关内容

  • 没有找到相关文章

最新更新