我想使用来自另一个文本框 (B) 的值验证在文本框 (A) 中输入的数字。在验证中,检查该值是否 a) 在恒定值范围内(->“Min”和“Max”),b) 是否小于用户通过文本框 B 提供的极限值(->“UserHighLimit”) . 此文本框 B 是同一窗口的不同视图(-> UserControl“SetLimit”)的一部分。为了说明该场景,请查看下面的简化代码。
用户控件(视图)“设置值”:
<UserControl.Resources>
<libraries:NumberToStringConverter x:Key="NumberToString"/>
</UserControl.Resources>
<UserControl.DataContext>
<viewmodels:ViewModelValue/>
</UserControl.DataContext>
<GroupBox Header="Set Value">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Label HorizontalAlignment="Right" VerticalAlignment="Center" Content="desired value"/>
<TextBox Grid.Column="1" Width="70" HorizontalAlignment="Left" VerticalAlignment="Center">
<TextBox.Text>
<Binding
Path="Range"
UpdateSourceTrigger="PropertyChanged"
Converter="{StaticResource NumberToString}">
<Binding.ValidationRules>
<libraries:ValueRule Min="1" Max="1000">
<libraries:ValueRule.ViewModel>
<viewmodels:ViewModelLimit/>
</libraries:ValueRule.ViewModel>
</libraries:ValueRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</Grid>
</GroupBox>
用户控件(视图)“设置限制”:
<UserControl.Resources>
<libraries:NumberToStringConverter x:Key="NumberToString"/>
<libraries:LimitRule x:Key="ValidateLimit" Min="1" Max="1000"/>
</UserControl.Resources>
<UserControl.DataContext>
<viewmodels:ViewModelLimit/>
</UserControl.DataContext>
<GroupBox Header="Set Limit">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Label HorizontalAlignment="Right" VerticalAlignment="Center" Content="Limit:"/>
<TextBox Grid.Column="1" Width="70" HorizontalAlignment="Left" VerticalAlignment="Center">
<TextBox.Text>
<Binding
Path="UserHighLimit"
UpdateSourceTrigger="PropertyChanged"
Converter="{StaticResource NumberToString}">
<Binding.ValidationRules>
<StaticResource ResourceKey="ValidateLimit"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</Grid>
</GroupBox>
使用绑定的 ViewModel 进行验证:
public class ValueRule : ValidationRule
{
public ushort Min { get; set; }
public ushort Max { get; set; }
public ViewModelLimit ViewModel { get; set; }
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
ushort uservalue = 0;
ushort uhlimit = ViewModel.UserHighLimit;
try
{
if (((string)value).Length > 0)
uservalue = ushort.Parse((String)value);
}
catch (Exception e)
{
return new ValidationResult(false, $"Illegal characters or {e.Message}");
}
switch (uhlimit > Max)
{
case true:
if ((uservalue < Min) || (uservalue > Max))
{
return new ValidationResult(false, $"Please enter a value in the range: {Min}-{Max}.");
}
break;
case false:
if (uservalue < Min || uservalue > uhlimit)
{
return new ValidationResult(false, $"Please enter a value in the range: {Min}-{uhlimit}.");
}
break;
}
return ValidationResult.ValidResult;
给定的代码运行无异常,但用于我的 TextBox 验证的 ViewModel(->“ViewModelLimit”)的绑定似乎实例化了一个自己的对象。因此,限制值(“UserHighLimit”)始终是 ViewModel 构造函数的初始值,即使在作为 DataContext 的 ViewModel 实例中限制已经更改。我可能希望保持我的视图的 CodeBehind 干净并通过 XAML 实例化 DataContext。
验证规则不是依赖对象,因此原则上不可能绑定其属性。
从您的问题来看,尚不清楚您创建 ViewModel 的动态程度如何。如果它们在窗口启动时创建一次,那么您可以在窗口资源中创建它们的实例,然后从那里获取它们。
<Window.Resources>
<local:MainViewModel x:Key="vm"/>
<viewmodels:ViewModelValue x:Key="vmValue"/>
<viewmodels:ViewModelLimit x:Key="vmLimit"/>
</Window.Resources>
<UserControl x:Class="*************.SetValue"
**********************
DataContext="{StaticResource vmValue}">
<UserControl x:Class="*************.SetLimit"
**********************
DataContext="{StaticResource vmLimit}">
<Binding.ValidationRules>
<libraries:ValueRule Min="1" Max="1000" ViewModel="{StaticResource vmLimit}"/>
</Binding.ValidationRules>
如果您的应用程序可能的话,我还建议在应用程序资源中创建实例。
如果实例的创建是动态发生的(它们被创建多次,它们之间的连接不同),那么很可能您将无法仅在 XAML 中实现这一点。正如 Clemens 上面所写,您将需要创建某种通用逻辑结构来统一您的 ViewModel。