1

我们有一个 DependencyObject,它将 Value 属性定义为 DP。它还定义了一个 Presets 集合,表示一些预定义值的友好名称。

我们的 UI 应该工作的方式是当我们绑定到 Value 属性时,如果该值与预设匹配,我们显示友好名称,否则我们直接显示该值。

使用转换器已经过时了,因为没有可靠的方法既可以传入 Presets(它们是按项目定义的,它们不是共享的)也可以进行双向绑定,所以我们的想法是在对象上公开 FriendlyValue 属性并将其用于 UI 中的绑定,让它在内部处理转换。

由于 FriendlyValue 依赖于已经存在的 Value DependencyProperty,我们认为我们只需将转换逻辑包装在 CLR getter/setter 中,但这意味着当实际 Value DP 发生变化时,它需要通知 UI FriendlyValue 也已更新,并且由于 FriendlyValue 是 CLR 属性,因此我们需要为该特定属性支持 INPC。

我的问题是,处理这个问题的正确/建议方法是,还是我应该使用第二个 DP,监视其更改处理程序并相应地设置另一个属性,添加状态变量以阻止一个设置另一个,然后设置首先,然后再次更新另一个,等等。

这是对象属性的代码...

public static readonly DependencyProperty PresetsProperty = DependencyProperty.Register(
    "Presets",
    typeof(List<Preset>),
    typeof(MyObject),
    new UIPropertyMetadata(null));

public List<Preset> Presets
{
    get { return (List<Preset>)GetValue(PresetsProperty); }
    set { SetValue(PresetsProperty, value); }
}

public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
    "Value",
    typeof(string),
    typeof(MyObject),
    new UIPropertyMetadata(null, (s,e) => {

        var myObject = (MyObject)s;

        myObject.OnPropertyChanged("FriendlyValue");

    }));

public string Value
{
    get { return (string)GetValue(ValueProperty); }
    set { SetValue(ValueProperty, value); }
}


public string FriendlyValue
{
    get
    {
        var foundPreset = Presets.FirstOrDefault(preset => preset.Value == this.Value);
        return (foundPreset != null)
            ? foundPreset.FriendlyName
            : this.Value;
    }
    set
    {
        var foundPreset = Presets.FirstOrDefault(preset => preset.FriendlyName == value);

        this.Value = (foundPreset != null)
            ? foundPreset.Value
            : value;

        // Note: We don't raise INPC notification here.  It's raised in the Value's change handler
    }
}

#region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        if(PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

#endregion

那么这是否被认为是内置转换器行为的良好做法?

4

1 回答 1

0

为什么不同时创建ValueFriendlyValue依赖属性?我认为没有理由同时使用两种技术。

考虑:

using Preset = Tuple<string, string>;

public class MyObject : DependencyObject
{
    private readonly IList<Tuple<string, string>> _presets = new List<Preset> {
        new Preset("1", "good"),
        new Preset("2", "bad"),
    };

    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
        "Value", typeof(string), typeof(MyObject),
        new PropertyMetadata(null,
            (o, e) => ((MyObject)o).ValuePropertyChanged((string)e.NewValue)));
    private static readonly DependencyProperty FriendlyValueProperty = DependencyProperty.Register(
        "FriendlyValue", typeof(string), typeof(MyObject),
        new PropertyMetadata(null,
            (o, e) => ((MyObject)o).FriendlyValuePropertyChanged((string)e.NewValue)));

    public string Value
    {
        get { return (string)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    public string FriendlyValue
    {
        get { return (string)GetValue(FriendlyValueProperty); }
        set { SetValue(FriendlyValueProperty, value); }
    }

    private void ValuePropertyChanged (string newValue)
    {
        var preset = _presets.FirstOrDefault(p => p.Item1 == newValue);
        FriendlyValue = preset != null ? preset.Item2 : newValue;
    }

    private void FriendlyValuePropertyChanged (string newValue)
    {
        var preset = _presets.FirstOrDefault(p => p.Item2 == newValue);
        Value = preset != null ? preset.Item1 : newValue;
    }
}

笔记:

  1. 为简洁起见简化了预设代码。
  2. 这不会导致堆栈溢出,因为如果值未更改,则不会调用更改回调。

我希望我正确理解了你的逻辑。有一个问题:如果您FriendlyValue从预设更改为友好值之一,这将更改为Value找到的预设的值,进而更改FriendlyValue为预设的名称。我不知道这种行为是否是预期的。

于 2013-09-11T23:25:49.203 回答