gpt4 book ai didi

wpf - 使用 BindingExpression 调用 ValidationStep ="UpdatedValue"的 ValidationRule,而不是更新值

转载 作者:行者123 更新时间:2023-12-02 03:01:14 26 4
gpt4 key购买 nike

我开始在 WPF 应用程序中使用 ValidationRules,但很困惑。

我有以下简单规则:

class RequiredRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
if (String.IsNullOrWhiteSpace(value as string))
{
return new ValidationResult(false, "Must not be empty");
}
else
{
return new ValidationResult(true, null);
}

}
}

在 XAML 中使用如下:

<TextBox>
<TextBox.Text>
<Binding Path="Identity.Name">
<Binding.ValidationRules>
<validation:RequiredRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>

大部分都按照我的预期工作。我很惊讶地发现我的源属性 (Identity.Name) 没有被设置;我有一个撤消函数,它永远不会看到更改,并且除了重新输入它之外没有其他方法可以恢复该值(不好)。

微软的Data Binding Overview底部描述了验证过程,很好地解释了这种行为。基于此,我希望将我的 ValidationStep 设置为 UpdatedValue

<validation:RequiredRule ValidationStep="UpdatedValue"/>

这就是我觉得事情变得奇怪的地方。我得到的是 System.Windows.Data.BindingExpression,而不是使用已设置的属性值(即字符串)来调用 Validate()!我在 Microsoft 文档中没有看到任何描述此行为的内容。

在调试器中,我可以看到源对象(TextBoxDataContext),导航到属性的路径,并看到该值已设置。但是,我没有看到任何在验证规则中获取正确属性的好方法。

注意:使用 ValidationStep 作为 ConvertedProposedValue,我得到输入的字符串(我没有使用转换器),但它也会阻止源属性更新正如预期的那样,验证失败。通过 CommitedValue,我得到 BindingExpression 而不是字符串。

这里有几个问题:

  1. 为什么根据 ValidationStep 设置传递给 Validate() 的参数类型不一致?

  2. 如何从 BindingExpression 获取实际值?

  3. 或者,有没有一种好的方法可以让用户将 TextBox 恢复到以前的(有效)状态? (正如我提到的,我自己的撤消函数永远不会看到变化。)

最佳答案

我已经解决了从 BindingExpression 中提取值的问题,但有一点限制。

首先,一些更完整的 XAML:

<Window x:Class="ValidationRuleTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ValidationRuleTest"
Title="MainWindow" Height="100" Width="525">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="String 1"/>
<TextBox Grid.Column="1">
<TextBox.Text>
<Binding Path="String1" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:RequiredRule ValidationStep="RawProposedValue"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<TextBlock Text="String 2" Grid.Row="1"/>
<TextBox Grid.Column="1" Grid.Row="1">
<TextBox.Text>
<Binding Path="String2" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:RequiredRule ValidationStep="UpdatedValue"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</Grid>
</Window>

请注意,第一个 TextBox 使用 ValidationStep="RawProposeValue" (默认值),而第二个 TextBox 使用 ValidationStep="UpdatedValue",但两者使用相同的验证规则。

一个简单的 ViewModel(忽略 INPC 和其他有用的东西):

class MainWindowViewModel
{
public string String1
{ get; set; }

public string String2
{ get; set; }
}

最后,新的RequiredRule:

class RequiredRule : ValidationRule
{
public override ValidationResult Validate(object value,
System.Globalization.CultureInfo cultureInfo)
{
// Get and convert the value
string stringValue = GetBoundValue(value) as string;

// Specific ValidationRule implementation...
if (String.IsNullOrWhiteSpace(stringValue))
{
return new ValidationResult(false, "Must not be empty");
}
else
{
return new ValidationResult(true, null);
}
}

private object GetBoundValue(object value)
{
if (value is BindingExpression)
{
// ValidationStep was UpdatedValue or CommittedValue (Validate after setting)
// Need to pull the value out of the BindingExpression.
BindingExpression binding = (BindingExpression)value;

// Get the bound object and name of the property
object dataItem = binding.DataItem;
string propertyName = binding.ParentBinding.Path.Path;

// Extract the value of the property.
object propertyValue = dataItem.GetType().GetProperty(propertyName).GetValue(dataItem, null);

// This is what we want.
return propertyValue;
}
else
{
// ValidationStep was RawProposedValue or ConvertedProposedValue
// The argument is already what we want!
return value;
}
}
}

如果 GetBoundValue() 方法获得 BindingExpression,它将挖掘出我关心的值,如果不是,则简单地回退参数。真正的关键是找到“路径”,然后使用它来获取属性及其值。

限制:在我最初的问题中,我的绑定(bind)具有 Path="Identity.Name",因为我正在深入研究 ViewModel 的子对象。这将不起作用,因为上面的代码期望路径直接指向绑定(bind)对象上的属性。幸运的是,我已经展平了 ViewModel,因此情况不再如此,但解决方法可能是首先将控件的数据上下文设置为子对象。

我想对 Eduardo Brites 给予一些信任,因为他的回答和讨论让我重新开始深入研究这个问题,并且确实为他的难题提供了一部分。另外,虽然我打算完全放弃 ValidationRules 并使用 IDataErrorInfo 代替,但我喜欢他关于将它们一起用于不同类型和复杂性验证的建议。

关于wpf - 使用 BindingExpression 调用 ValidationStep ="UpdatedValue"的 ValidationRule,而不是更新值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10342715/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com