什么时候应用依赖属性?

时间:2015-01-31 11:53:27

标签: c# wpf xaml dependency-properties

我正在做一些培训项目。它应该将数字转换为不同的字符串。 继承了转换后的Control,并在我的主窗口中使用它。 所以第一个问题是我想基于我传递给OutputFormatProperty的值创建转换器的实例,所以在这种情况下我创建了应该是类型OctalConverter的转换器,但我获得了默认值,为什么呢? 另一件事是我不想通过将它绑定到CurrentValue来改变转换器中的InputValue,它与NotifyPropertyChanged一起使用,但它似乎没有那样工作。

public partial class ConverterDisplay : UserControl {

    private const int DEFAULT_INPUT_VALUE = 0;
    private readonly ObservableCollection <DisplayField> _displayFields;
    private AbstractNumberConverter _converter;

    public static readonly DependencyProperty InputValueProperty = DependencyProperty.Register (
        "InputValue",
        typeof(int),
        typeof(ConverterDisplay),
        new PropertyMetadata (DEFAULT_INPUT_VALUE));

    public static readonly DependencyProperty OutputFormatProperty = DependencyProperty.Register (
        "OutputFormat",
        typeof(NumberSystems),
        typeof(ConverterDisplay),
        new FrameworkPropertyMetadata (NumberSystems.Binary));


    public int InputValue {
        get {
            return (int) GetValue (InputValueProperty);
        }
        set {
            SetValue (InputValueProperty, value);
            UpdateDisplay ();
        }
    }
    public NumberSystems OutputFormat {
        get {
            return (NumberSystems) GetValue (OutputFormatProperty); 

        }
        set {
            SetValue (OutputFormatProperty, value);
        }
    }

    public ObservableCollection <DisplayField> DisplayFields {
        get { return _displayFields; }
    }

    public ConverterDisplay () {
        _displayFields = new ObservableCollection<DisplayField> ();
        InitializeComponent ();
        CreateConverter ();
    }

    private void UpdateDisplay () {
        var convertedNumberString = _converter.GetString (InputValue);

        if (_displayFields.Count > convertedNumberString.Length)
            ResetDisplayFields ();

        while (_displayFields.Count < convertedNumberString.Length)
            AddDisplayField ();

        UpdateValues (convertedNumberString);
    }

    private void UpdateValues (string convertedString) {
        if (_displayFields.Count == 0) return;

        for (int i = 0; i < _displayFields.Count; i++) {
            _displayFields [i].NumberValue = convertedString [i];
        }
    }

    private void AddDisplayField () {
        _displayFields.Insert (
            0,
            new DisplayField ((int)OutputFormat, _displayFields.Count));
    }

    private void ResetDisplayFields () {
        _displayFields.Clear ();
    }

    private void CreateConverter () {
        switch (OutputFormat) {
            case NumberSystems.Binary:
                _converter = new BinaryConverter ();
                break;
            case NumberSystems.Octal:
                _converter = new OctalConverter ();
                break;
            case NumberSystems.Hexadecimal:
                _converter = new HexadecimalConverter ();
                break;
        }
    }
}

public enum NumberSystems {
    Binary = 2,
    Octal = 8,
    Hexadecimal = 16
}

然后在主窗口中我试图使用该控件

 <converters:ConverterDisplay x:Name="octConverter"
                              InputValue="{Binding ElementName=Window,Path=CurrentValue}"
                              OutputFormat="Octal"/>

以防万一

public int CurrentValue {
        get { return _currentValue; }
        set {
            if (value == _currentValue)
                return;
            ValidateNewValue (value);
            OnPropertyChanged ();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged ([CallerMemberName] string propertyName = null) {
        PropertyChanged?.Invoke (this, new PropertyChangedEventArgs (propertyName));
    }

===========================

编辑#1

我真的不喜欢这个解决方案但我在ConverterDisplay中创建了公共方法来创建转换器,它在MainWindow初始化之后被调用,所以现在转换器是正确的。 另一件事是我如何将我的UpdateDisplay方法绑定到InputValueProperty?我通过验证发现它获得了正确的值,但我无法看到如何在不创建静态内容的情况下运行该方法。

1 个答案:

答案 0 :(得分:0)

关于你的第二个问题(将UpdateDisplay方法绑定到InputValueProperty:一般来说,在依赖属性的setter中调用任何方法不是最好的主意,因为在使用数据时从不调用此setter绑定以填充依赖项属性的值,如指出at MSDN

  

WPF XAML处理器使用属性系统方法进行依赖   加载二进制XAML和处理属性时的属性   依赖属性。这有效地绕过了财产   包装。实现自定义依赖项属性时,必须执行此操作   考虑到这种行为,应该避免放入任何其他代码   除属性系统方法GetValue之外的属性包装器   和SetValue。

相反,创建一个在InputValue内容发生变化时调用的回调方法,并从那里调用UpdateDisplay

public static readonly DependencyProperty InputValueProperty = DependencyProperty.Register (
    "InputValue",
    typeof(int),
    typeof(ConverterDisplay),
    new PropertyMetadata (DEFAULT_INPUT_VALUE, InputValueChangedCallback));


private static void InputValueChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
    var userControl = dependencyObject as ConverterDisplay;
    if (userControl != null)
        userControl.UpdateDisplay();
}