如何在没有调用属性的情况下使用带有WPF的IDataErrorInfo更改已更改的其他属性?

时间:2013-11-13 20:03:45

标签: c# .net wpf

我有2个文本框,1个用于最小值,另一个用于最大值。他们不能互相调用属性更改事件,因为这会搞乱其他一些功能。我的视图模型上有一个IDataErrorInfo接口,当一个文本框被验证时,另一个文本框也需要。

例如我正在寻找的验证是当最小值大于最大值时需要出现错误,但是这个错误可以从任一文本框中纠正,并且当这个文本框的错误需要被删除时发生。这可以通过让min和max属性调用彼此的属性更改事件来轻松实现,但我不能这样做,因为它会破坏其他功能。我需要另一种方式。有什么想法吗?

     #region Implementation of IDataErrorInfo

            /// <summary>
            /// Gets the error message for the property with the given name.
            /// </summary>
            /// <returns>
            /// The error message for the property. The default is an empty string ("").
            /// </returns>
            /// <param name="columnName">The name of the property whose error message to get. </param>
            public string this[string columnName]
            {
                get
                {
                    string error = null;
                    if (columnName == Reflection.GetPropertyName<ColorPaletteManagerViewModel>(m => m.MaximumColorValue) ||
                        columnName == Reflection.GetPropertyName<ColorPaletteManagerViewModel>(m => m.MinimumColorValue))
                    {
                        error = GetTimeGateError();
                    }
                    _errors[columnName] = error;                              
                    OnPropertyChanged<ColorPaletteManagerViewModel>(m => m.Error);
                    return error;
                }
            }

            /// <summary>
            /// Gets an error message indicating what is wrong with this object.
            /// </summary>
            /// <returns>
            /// An error message indicating what is wrong with this object. The default is an empty string ("").
            /// </returns>
            public string Error
            {
                get
                {
                    string[] allErrors =
                        _errors.Where(i => !string.IsNullOrWhiteSpace(i.Value)).Select(m => m.Value).ToArray();
                    return string.Join(Environment.NewLine, allErrors);
                }
            }


            #endregion

    private string GetTimeGateError()
            {
                string error = null;

                if (MinimumColorValue > MaximumColorValue)
                {
                    error = string.Format("The Maximum Color Range Cannot be Less Then The Minimum Color Range");
                }

                return error;
            }

 /// <summary>
        /// Gets or sets the maximum color value.
        /// </summary>
        public float MaximumColorValue
        {
            get { return _maximumColorValue; } 
            set
            {
                if (_maximumColorValue != value)
                {
                    _maximumColorValue = value;
                    OnPropertyChanged(i => i.MaximumColorValue);
                }
            }
        }

        /// <summary>
        /// Gets or sets the minimum color value.
        /// </summary>
        public float MinimumColorValue
        {
            get { return _minimumColorValue; }
            set
            {
                if (_minimumColorValue != value)
                {
                    _minimumColorValue = value;
                    OnPropertyChanged(i => i.MinimumColorValue);
                }
            }
        }

xaml:

 <UserControl.Resources>
        <Style TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="ToolTip"
                            Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                            Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
            </Style>
    </UserControl.Resources>

     <TextBox Name="_minColorValue" 
                         Width="55" 
                         Height="22"
                         Grid.Row="1" 
                         Grid.Column="1" 
                         Margin="0,-4,0,0"
                         IsEnabled="{Binding ElementName=_override, Path=IsChecked}">
                    <TextBox.Text>
                        <Binding Path="MinimumColorValue" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged" Delay="500">
                            <Binding.ValidationRules>
                                <ValidationRules:NumberValidationRule/>
                            </Binding.ValidationRules>
                        </Binding>
                    </TextBox.Text>
                </TextBox>

     <TextBox Name="_maxColorValue"
                         Width="55" 
                         Height="22"
                         Margin="0,-4,0,0"
                         HorizontalAlignment="Left" 
                         IsEnabled="{Binding ElementName=_override, Path=IsChecked}"
                         Grid.Column="1" 
                         Grid.Row="2">
                    <TextBox.Text>
                        <Binding Path="MaximumColorValue" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged" Delay="500">
                            <Binding.ValidationRules>
                                <ValidationRules:NumberValidationRule/>
                            </Binding.ValidationRules>
                        </Binding>
                    </TextBox.Text>
                </TextBox>

2 个答案:

答案 0 :(得分:3)

如果您的目标是.NET 4.5,则可以使用INotifyDataErrorInfo interface代替。这个界面几乎是IDataErrorInfo的更好版本,它包含一个ErrorsChanged事件,告诉WPF重新评估给定属性或所有属性的错误。然后你可以根据需要简单地举起这个事件。

不幸的是,这个界面仅在.NET 4.5之后才可用,所以希望它可供你使用。

答案 1 :(得分:1)

我建议您使用附加属性来解决此问题。

创建TextBox类型的附加属性。

将附加属性放在第一个TextBox上,并使用x:Reference或Binding ElementName将其值设置为第二个TextBox的值。

将相同的附加属性放在另一个TextBox上,这次将其值设置为第一个TextBox的引用。

现在每个TextBox都知道另一个。多数民众赞成你赢了。

现在您需要做的只是在更新源或更改文本输入或其他内容时使另一个TextBox无效或更改。

你可以随心所欲地做任何事情,因为他们总是会知道另一个。

这个建议怎么样?我希望我可以发表评论,但它不适合。