如何绑定到另一个视图的DataContext ViewModel?

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

我想使用来自另一个文本框 (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。

c# wpf mvvm data-binding
1个回答
0
投票

验证规则不是依赖对象,因此原则上不可能绑定其属性。
从您的问题来看,尚不清楚您创建 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。

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