我有一个ObservableCollection<dynamic>
类,XAML 拒绝绑定到包含对象的属性。
我知道我在 XAML 支持的地方读到过dynamic
,DyanmicObject
所以我很困惑为什么这不起作用。其他问题,例如这个问题,非常没有帮助:
我可以在 WinRT / Windows 8 商店应用程序中绑定 DynamicObject
我在运行时(以及在设计时将鼠标悬停在我{Binding
的 s 上时在设计器中)收到此错误:
Error: BindingExpression path error: 'DisplayName' property not found on 'PremiseMetro.Light, PremiseMetro, ... BindingExpression: Path='DisplayName' DataItem='PremiseMetro.Light, PremiseMetro, ... target element is 'Windows.UI.Xaml.Controls.TextBlock' (Name='null'); target property is 'Text' (type 'String')
请帮忙!
谢谢。
一个测试ObservableObject
类:
class Light : DynamicObject, INotifyPropertyChanged {
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
public event PropertyChangedEventHandler PropertyChanged;
public override bool TryGetMember(GetMemberBinder binder, out object result) {
string name = binder.Name;
result = null;
// If the property name is found in a dictionary,
// set the result parameter to the property value and return true.
// Otherwise, return false.
object prop;
if (_properties.TryGetValue(name, out prop)) {
result = prop;
return true;
}
return false;
}
// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember(SetMemberBinder binder, object value) {
string name = binder.Name;
_properties[name] = value;
if (CoreApplication.MainView.CoreWindow.Dispatcher.HasThreadAccess)
OnPropertyChanged(name);
else
CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
CoreDispatcherPriority.Normal, () => OnPropertyChanged(name));
// You can always add a value to a dictionary,
// so this method always returns true.
return true;
}
public object GetMember(string propName) {
var binder = Binder.GetMember(CSharpBinderFlags.None,
propName, GetType(),
new List<CSharpArgumentInfo> {
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
});
var callsite = CallSite<Func<CallSite, object, object>>.Create(binder);
return callsite.Target(callsite, this);
}
/// <summary>
/// Sets the value of a property.
/// </summary>
/// <param name="propertyName">Name of property</param>
/// <param name="val">New value</param>
/// <param name="fromServer">If true, will not try to update server.</param>
public void SetMember(String propertyName, object val) {
var binder = Binder.SetMember(CSharpBinderFlags.None,
propertyName, GetType(),
new List<CSharpArgumentInfo> {
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
});
var callsite = CallSite<Func<CallSite, object, object, object>>.Create(binder);
callsite.Target(callsite, this, val);
}
protected virtual void OnPropertyChanged(string propertyName) {
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
我的 MainViewMODEl 构造函数中的测试:
Light light = new Light();
((dynamic) light).DisplayName = "Test Light";
((dynamic) light).Brightness= "27%";
((dynamic) light).PowerState= false;
Lights = new ObservableCollection<dynamic> {
light
};
我的测试 XAML:
<Grid Margin="10" Width="1000" VerticalAlignment="Stretch">
<ListBox x:Name="GDOList" ItemsSource="{Binding Path=Lights}" >
<ListBox.ItemTemplate>
<DataTemplate >
<Grid Margin="6">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Path=DisplayName}" Margin="5" />
<TextBlock Text="{Binding Path=PowerState}" Margin="5" />
<TextBlock Text="{Binding Path=Brightness}" Margin="5" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Page>