在XAML中(特别是在通用Windows平台上)我可以使用索引器的属性路径表示法将数据绑定到索引属性。
e.g。给定类型Dictionary<string,string>
的数据源,我可以绑定到索引属性,如下所示:
<TextBlock Text="{Binding Dictionary[Property]}"/>
在上文中,TextBlock的DataContext被设置为具有字典属性的对象,如下所示:
public class DataObject
{
public Dictionary<string,string> Dictionary { get; } = new Dictionary<string,string> {["Property"]="Value"};
}
我的问题是,是否可以在不使用索引器表示法的情况下绑定到索引属性,而是使用标准属性绑定的语法?
即
<TextBlock Text="{Binding Dictionary.Property}"/>
从我最初的测试来看,这似乎不起作用。有一种简单的方法可以使它工作吗?我想使用具有索引属性的数据源对象(在本例中类似于Dictionary,但可能只是一个简单的对象)。我不想使用动态对象。
答案 0 :(得分:0)
没有语法可以做你想要的,我害怕。标准属性绑定的语法适用于标准属性,例如
<TextBlock Text="{Binding Dictionary.Count}" />
...将绑定到字典的Count
属性(或任何对象)。你需要它们括号......
修改强>
如果你真的讨厌括号,我能找到的最接近的东西就是使用带参数的转换器。例如:
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
IDictionary<string, string> dictionary = value as IDictionary<string, string>;
string dictionaryValue;
if (dictionary != null && dictionary.TryGetValue(parameter as string, out dictionaryValue))
{
return dictionaryValue;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotSupportedException();
}
}
XAML:
<Page
x:Class="UWP.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uwp="using:UWP">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<uwp:MyConverter x:Key="MyConverter" />
</Grid.Resources>
<Grid.DataContext>
<uwp:DataObject />
</Grid.DataContext>
<TextBlock
Text="{Binding Dictionary, ConverterParameter=Property1, Converter={StaticResource MyConverter}}" />
</Grid>
</Page>
......这是一种迂回的方式,最终会出现比括号更难读的东西。
答案 1 :(得分:0)
很久以前,Windows 8应用程序模板中就有这个ObservableDictionary
类,它可以满足您的需求。它不是Dictionary<string, string>
,但是您可以将Dictionary
中的值复制到ObservableDictionary
在ViewModel中声明一个ObservableDictionary
属性,然后像通常的属性一样绑定到其索引器:
using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Foundation.Collections;
namespace MyApp
{
public class ObservableDictionary : IObservableMap<string, object>
{
private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs<string>
{
public ObservableDictionaryChangedEventArgs(CollectionChange change, string key)
{
this.CollectionChange = change;
this.Key = key;
}
public CollectionChange CollectionChange { get; private set; }
public string Key { get; private set; }
}
private Dictionary<string, object> _dictionary = new Dictionary<string, object>();
public event MapChangedEventHandler<string, object> MapChanged;
private void InvokeMapChanged(CollectionChange change, string key)
{
var eventHandler = MapChanged;
if (eventHandler != null)
{
eventHandler(this, new ObservableDictionaryChangedEventArgs(change, key));
}
}
public void Add(string key, object value)
{
this._dictionary.Add(key, value);
this.InvokeMapChanged(CollectionChange.ItemInserted, key);
}
public void Add(KeyValuePair<string, object> item)
{
this.Add(item.Key, item.Value);
}
public bool Remove(string key)
{
if (this._dictionary.Remove(key))
{
this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
return true;
}
return false;
}
public bool Remove(KeyValuePair<string, object> item)
{
object currentValue;
if (this._dictionary.TryGetValue(item.Key, out currentValue) &&
Object.Equals(item.Value, currentValue) && this._dictionary.Remove(item.Key))
{
this.InvokeMapChanged(CollectionChange.ItemRemoved, item.Key);
return true;
}
return false;
}
public virtual object this[string key]
{
get
{
return this._dictionary[key];
}
set
{
this._dictionary[key] = value;
this.InvokeMapChanged(CollectionChange.ItemChanged, key);
}
}
public void Clear()
{
var priorKeys = this._dictionary.Keys.ToArray();
this._dictionary.Clear();
foreach (var key in priorKeys)
{
this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
}
}
public ICollection<string> Keys
{
get { return this._dictionary.Keys; }
}
public bool ContainsKey(string key)
{
return this._dictionary.ContainsKey(key);
}
public bool TryGetValue(string key, out object value)
{
return this._dictionary.TryGetValue(key, out value);
}
public ICollection<object> Values
{
get { return this._dictionary.Values; }
}
public bool Contains(KeyValuePair<string, object> item)
{
return this._dictionary.Contains(item);
}
public int Count
{
get { return this._dictionary.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
return this._dictionary.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this._dictionary.GetEnumerator();
}
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
int arraySize = array.Length;
foreach (var pair in this._dictionary)
{
if (arrayIndex >= arraySize) break;
array[arrayIndex++] = pair;
}
}
}
}
答案 2 :(得分:0)
class DictionaryXamlWrapper : DynamicObject, INotifyPropertyChanged
{
#region PropertyChangedFunctional
public void OnPropertyChanged([CallerMemberName] string aProp = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(aProp));
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
Dictionary<string, object> members = new Dictionary<string, object>();
// установка свойства
public override bool TrySetMember(SetMemberBinder binder, object value)
{
members[binder.Name] = value;
OnPropertyChanged(binder.Name);
return true;
}
// получение свойства
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
if (members.ContainsKey(binder.Name))
{
result = members[binder.Name];
return true;
}
return false;
}
}
当然,如果不需要,可以删除INotifyPropertyChanged函数。
以及所需的用法
<TextBlock Text="{Binding DictionaryXamlWrapper.TestField}"/>