0

編集: これは、この投稿の元のバージョンの簡略化された更新です。

WPFでは、 TextBox (xaml)のTextプロパティと同期する *DependencyProperty 'Value' を使用するUserControl ('NumericTextBox' と呼ばれる)を実装しました。

<TextBox.Text>
  <Binding Path="Value" 
           Mode="TwoWay"
           ValidatesOnDataErrors="True"
           NotifyOnValidationError="True"
           UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>

検証のために、IDataErrorInfoインターフェイス (xaml.cs)を使用します。

public partial class NumericTextbox : Textbox, IDataErrorInfo {
    public double Value {
        get { return (double)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(double),  
                                    typeof(NumericTextBox), 
                                    new PropertyMetadata(default(double)));

    public string this[string columnName]
    {
        // Never gets called!
        get { /* Some validation rules here */ }
    }
}

ソース コードに記載されているように、getプロパティは実際には呼び出されないため、検証は行われません。問題の理由がわかりますか?

Edit2 :ethicallogicsの回答に基づいて、コードを再構築しました。NumericTextBoxは、NumericTextBoxによって宣言されたTextBoxのTextプロパティにバインドされるDependency Property Valueを提供する基礎となるビューモデル クラスを使用するようになりました。さらに、 NumericTextBoxはビューモデルをデータコンテキストとして使用します。ビューモデルは現在、Value プロパティの変更をチェックする責任があります。NumericTextBoxの値の制限はカスタマイズ可能であるため (たとえば、最小値を調整できます)、これらの設定をビューモデル オブジェクトに転送します。

4

2 に答える 2

0

依存関係プロパティを作成するのではなく、このようにします。検証は、ControlまたはViewではなくViewModelで適用されます。このように試してみてください。これがお役に立てば幸いです。

public class MyViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    public MyViewModel()
    {
        Value = 30;
    }
    private double _value;

    [Range(1, 80, ErrorMessage = "out of range")]
    public double Value
    {
        get
        {
            return _value;
        }
        set
        {
            _value = value;
            ValidationMessageSetter("Value", value);
        }
    }

    private void ValidationMessageSetter(string propertyName, object value)
    {
        Notify(propertyName);
        string validationresult = ValidateProperty(propertyName, value);
        if (!string.IsNullOrEmpty(validationresult) && !_dataErrors.ContainsKey(propertyName))
            _dataErrors.Add(propertyName, validationresult);
        else if (_dataErrors.ContainsKey(propertyName))
                _dataErrors.Remove(propertyName);

    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    private void Notify(string str)
    { 
        if(PropertyChanged!=null)
            PropertyChanged(this,new PropertyChangedEventArgs(str));
    }

    private string ValidateProperty(string propertyName,object value)
    {
        var results = new List<ValidationResult>(2);
        string error = string.Empty;

        bool result = Validator.TryValidateProperty(
            value,
            new ValidationContext(this, null, null)
            {
                MemberName = propertyName
            },
            results);

        if (!result && (value == null || ((value is int || value is long) && (int)value == 0) || (value is decimal && (decimal)value == 0)))
            return null;

        if (!result)
        {
            ValidationResult validationResult = results.First();
            error = validationResult.ErrorMessage;
        }

        return error;    
    }

    #region IDataErrorInfo Members

    private Dictionary<string, string> _dataErrors = new Dictionary<string, string>();

    public string Error
    {
        get { throw new NotImplementedException(); }
    }

    public string this[string columnName]
    {
        get
        {
            if (_dataErrors.ContainsKey(columnName))
                return _dataErrors[columnName];
            else
                return null;
        }
    }

    #endregion
}

<TextBox Text="{Binding Value, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>

これがお役に立てば幸いです。

于 2012-07-25T13:48:34.313 に答える
0

インターフェイスは、を持つオブジェクトではなく、IDataErrorInfoにバインドされているオブジェクトに実装する必要がありますDependencyProperty

あなたの例では、このメカニズムを使用して検証を取得したい場合、ビューモデルはValueプロパティに対して以下のようなことをする必要があります:

public class ViewModel : IDataErrorInfo
{
    public string this[string columnName]
    {
        // Never gets called!
        get
        { 
            if (columnName == "Value")
                return GetValidationMessageForValueField();

            return null;
        }
    }
}

あなたが実際にやりたいことは、誰かがTextBox..?に数値以外の値を入力したときに検証することだと思います。この場合、おそらく使用するよりも別のアプローチを取りたいと思うでしょうIDataErrorInfo

于 2012-07-26T13:11:41.440 に答える