应用依赖项属性时



我现在正在做一些培训项目。它应该将数字转换为不同的字符串。这是转换后的控件,在主窗口中以底部的方式使用它。所以第一个问题是我想根据我传递给 OutputFormatProperty 的值创建转换器的实例,所以在这种情况下,我创建了应该是 OctalConverter 类型的转换器,但我得到了默认的转换器,为什么会这样?另一件事是,我不想通过将转换器中的 InputValue 绑定到 CurrentValue 来更改它,它适用于 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?我通过验证发现它获得了正确的值,但我看不出如何在不创建静态内容的情况下运行该方法。

关于你的第二个问题(将UpdateDisplay方法绑定到InputValueProperty: 通常,在依赖项属性的 setter 中调用任何方法并不是最好的主意,因为在使用数据绑定填充依赖项属性的值时,永远不会调用此 setter,如 MSDN 所述:

WPF XAML 处理器使用属性系统方法实现依赖关系 加载二进制 XAML 和处理以下属性时的属性 依赖项属性。这有效地绕过了属性 包装。实现自定义依赖项属性时,必须 考虑到此行为,并应避免将任何其他代码放入 属性系统方法 GetValue 以外的属性包装器 和设置值。

相反,创建一个每当 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();
}

最新更新