绑定到字典,自动创建缺少的条目

时间:2017-07-18 14:53:57

标签: c# wpf dictionary binding

通过输入键绑定到字典值非常简单:

<TextBox Text="{Binding SomeDictionary[someKey]}" />

但是条目必须存在:

public Dictionary<string, string> SomeDictionary { get; } = new Dictionary<string, string>
{
    { "someKey", "someValue" },
};

否则(例如空字典)抛出异常:

  

System.Windows.Data错误:17:无法从'SomeDictionary'获取'Item []'值(类型'String')(类型'Dictionary~2')。 BindingExpression:路径= SomeDictionary [someKey]; DataItem ='MainWindow'(Name =''); target元素是'TextBox'(Name =''); target属性是'Text'(类型'String')TargetInvocationException:'System.Reflection.TargetInvocationException:调用目标抛出了异常。 ---&GT; System.Collections.Generic.KeyNotFoundException:给定的键不在字典中。      在System.Collections.Generic.Dictionary`2.get_Item(TKey key)

有没有办法自动添加带有绑定键而不是异常指定的默认值的条目?

目前,如果在代码中完成绑定,则可以实现此目的:

if (!SomeDictionary.ContainsKey("someKey"))
    SomeDictionary.Add("someKey", "defaultValue");
textBox.SetBinding(TextBox.TextProperty, new Binding("[someKey]") { Source = SomeDictionary });

我正在寻找可重复使用的xaml解决方案。

我在考虑的事情:

  • 创建行为(附加属性)或标记扩展以运行与上面类似的代码;
  • 以某种方式捕获异常并重新绑定或其他什么?
  • 创建自己的Binding来做某事,但到底是什么?

也许有一种更简单的方法?

1 个答案:

答案 0 :(得分:0)

可能的解决方法是将字典包装到DynamicObject,这将允许拦截绑定调用getter / setter:

public class Wrapper<T> : DynamicObject, INotifyPropertyChanged
{
    readonly Dictionary<string, T> _dictionary;

    public Wrapper(Dictionary<string, T> dictionary)
    {
        _dictionary = dictionary;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        T value;
        if (!_dictionary.TryGetValue(binder.Name, out value))
        {
            value = default(T);
            _dictionary.Add(binder.Name, value);
        }
        result = value;
        return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        _dictionary[binder.Name] = (T)value;
        OnPropertyChanged(binder.Name);
        return true;
    }

    ...
}

然后使用它

public Wrapper<string> WrapperProperty { get; } = new Wrapper<string>(new Dictionary<string, string>
{
    //{ "someKey", "someValue" }, // no problems if commented
});

xaml中的绑定变为{Binding WrapperProperty.someKey}

奖励:INotifyPropertyChanged(未在代码中实现)使字典条目可观察,允许将多个元素绑定到相同的条目