4

I am trying to data bind a Xaml property to a property of a dynamic object. In this case the dynamic object is a JObject from the Json.Net library. JObject is a well behaved dynamic object and I've had no problems with it in the past. It makes for a lightweight way to go to/from json serialized objects and C# code.

In this case however the binding throws an exception at runtime.

The binding:

 <TextBlock Text="{Binding UserProfile.Value.name}"/>

where Value is a JObject and name a dynamic property (string)

The exception:

    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')

Curiously if I explicitly convert the JObject to an ExpandoObject the binding works.

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;
    }
}

For binding to dynamic objects to work does the data object need to be an ExpandoObject. Obviously the binding is interrogating the dataobject's type and using reflection to get the property and value. Is there special case logic for ExpandoObject and is ExpandoObject the only option for doing this?

UPDATE

As @dkozl points out this type of binding works with straight up WPF. I can get the desired behavior with this WPF window and dynamic property:

<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);
        }
    }
}

However with a WinRT 8.1 Store app this very similar binding produces an error:

<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);
        }
    }
}

Simple project that demonstrates this is here. Unfortunately it looks like a difference of behavior in WinRT binding.

dkackman
  • 15,179
  • 13
  • 69
  • 123
  • I've just tried simplest binding to `JObject` where context is set like `DataContext = JObject.Parse(@"{ 'name': 'James' }");` and it seems to work. I've also tried with `Value` property, just like yours, and it works without `ExpandoObject` convertion – dkozl May 26 '14 at 19:49
  • weird. The object in question is generated by JsonConvert.DeserializeObject(json). I'll play around with it a bit see if I can figure anything else out – dkackman May 26 '14 at 20:31
  • It also works if instead of `JObject.Parse(...)` I do `JsonConvert.DeserializeObject(...)`. Maybe try it on a clean project and see at which point it breaks – dkozl May 26 '14 at 20:47
  • Fresh project with no extraneous bits same binding error. This is a .net 4.5, WinRt 8.1 universal app building in vs.net 2013. Are you seeing success in straight up WPF? – dkackman May 26 '14 at 21:14
  • Simple Windows WPF app, .NET4, VS2013 and can't remember what version of Json.NET but latest installed from Nuget – dkozl May 26 '14 at 21:26
  • Simple reproducing project here: https://onedrive.live.com/redir?resid=EE5497473B4CE9CD!13652&authkey=!AFfbSRNG7HI4Gjs&ithint=file%2c.zip – dkackman May 26 '14 at 21:26

0 Answers0