我正在尝试将Xaml属性数据绑定到动态对象的属性。在这种情况下,动态对象是Json.Net library中的JObject
。 JObject
是一个表现良好的动态对象,过去我对它没有任何问题。它使得json序列化对象和C#代码的轻量级方式成为可能。
在这种情况下,绑定会在运行时抛出异常。
绑定:
<TextBlock Text="{Binding UserProfile.Value.name}"/>
其中Value
是JObject
而name
是动态属性(字符串)
例外:
Error: BindingExpression path error: 'name' property not found on 'Newtonsoft.Json.Linq.JObject,
Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'.
BindingExpression: Path='UserProfile.Value.name' DataItem='Google.Apps.ViewModel.MainViewModel';
target element is 'Windows.UI.Xaml.Controls.TextBlock' (Name='null'); target property is 'Text'
(type 'String')
奇怪的是,如果我将JObject显式转换为ExpandoObject,则绑定可以正常工作。
private dynamic _value; // set to a deserialized JObject elsewhere
public dynamic Value
{
get
{
if (_value != null) // debug code
{
dynamic o = new ExpandoObject();
o.name = _value.name;
return o;
}
return _value;
}
}
要绑定到动态对象,数据对象必须是ExpandoObject
。显然,绑定是询问dataobject的类型并使用反射来获取属性和值。 ExpandoObject
是否有特殊情况逻辑,而ExpandoObject
是执行此操作的唯一选择吗?
更新
正如@dkozl指出这种类型的绑定可以直接使用WPF。我可以使用此WPF窗口和动态属性获得所需的行为:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock FontSize="36" Width="920">Label</TextBlock>
<TextBlock Text="{Binding Path=TheName.name, ElementName=root}" FontSize="36"/>
</StackPanel>
</Grid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public dynamic TheName
{
get
{
string json = @"{ 'name': 'James' }";
return JsonConvert.DeserializeObject<dynamic>(json);
}
}
}
然而,对于WinRT 8.1 Store应用程序,这种非常相似的绑定会产生错误:
<Page
x:Name="root"
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Vertical">
<TextBlock FontSize="36" >Label</TextBlock>
<TextBlock Text="{Binding Path=TheName.name, ElementName=root}" FontSize="36"/>
</StackPanel>
</Grid>
</Page>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public dynamic TheName
{
get
{
string json = @"{ 'name': 'James' }";
return JsonConvert.DeserializeObject<dynamic>(json);
}
}
}
演示此内容的简单项目是here。不幸的是,它看起来像是WinRT绑定中的行为差异。