0

I am trying to bind to a GridLength instance in a Windows Store app (compiled with the Visual Studio 2013 compiler) in C++/CX, but for some reason I keep getting the following error at runtime:

Error: Converter failed to convert value of type 'Windows.Foundation.IReference`1<Windows.UI.Xaml.GridLength>' to type 'GridLength'; BindingExpression: Path='MyHeight' DataItem='MyNamespace.MyObject'; target element is 'Windows.UI.Xaml.Controls.RowDefinition' (Name='null'); target property is 'Height' (type 'GridLength').

My code essentially looks like:

namespace MyNamespace
{
    [Windows::UI::Xaml::Data::Bindable]
    public ref class MyObject sealed
    {
        property Windows::UI::Xaml::GridLength MyHeight
        {
            Windows::UI::Xaml::GridLength get() { return myHeight; }
        }
    }
}

and my XAML file essentially looks like:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="{Binding MyHeight}"/>
    </Grid.RowDefinitions>
</Grid>

Just FYI, other properties in my class are binding properly. The issue appears to only be with the GridLength value struct. It is obviously finding the property correctly, but for some reason it can't match up the types.

Duncan
  • 980
  • 6
  • 17

2 Answers2

2

A RowDefinition is not a FrameworkElement, so it doesn't have a DataContext. Binding won't work here. You can put a Rectangle in that row though, set the row height to Auto and bind the Rectangle.Height to a property you want. That could work for some scenarios. For others there might be better solutions, but you would need to specify what exactly you are trying to achieve.

Filip Skakun
  • 31,624
  • 6
  • 74
  • 100
  • That's quite disappointing. [There is even a post on SO suggesting that this should be possible](http://stackoverflow.com/questions/147908/how-do-i-databind-a-columndefinitions-width-or-rowdefinitions-height/147928#147928). Your rectangle idea seems far too tedious since I need to split the space of n `TextBlock`s between n lines, only some are not visible, and thus some wrap. With your suggestion, I would have to actively listen to the total height (which already breaks the MVVM pattern), and divide, etc. – Duncan Jul 08 '13 at 15:41
  • That answer is for WPF and as the comment rightfully suggests - it is wrong to put a GridLength in a view model. Perhaps a `StackPanel` or a [`UniformGrid`](https://winrtxamltoolkit.codeplex.com/SourceControl/latest#WinRTXamlToolkit/Controls/UniformGrid/UniformGrid.cs) would be a better layout control in your case or some other panel, custom control or attached property to control the layout. Remember, using MVVM doesn't mean you can't have custom controls with code behind, dependency properties etc. – Filip Skakun Jul 08 '13 at 16:37
  • Ahh, I see. Thanks. I wasn't planning on keeping the `GridLength` in my view model. Instead I was (eventually) going to make it an integer and then provide a converter on the binding. Looks like that idea's hopeless though.. – Duncan Jul 08 '13 at 22:12
  • An easy way to get what you want might be to simply add an attached property to your grid that binds to an int and automatically updates the grid's RowDefinitions. In fact I have blogged about one such solution before for WPF and it should work just as well for WinRT. Check [this post](http://blog.onedevjob.com/2011/04/19/using-attached-properties-to-style-rowdefinitions-of-a-grid-in-wpf/). – Filip Skakun Jul 09 '13 at 15:12
  • Thanks for the suggestion. I ended up listening for the `DataContext` to change and then set a visual state (which ended up being a wonderful solution for me). From there, it was trivial to set the properties I need correctly (btw, I ended up changing `RowSpan` instead of `RowDefinition`s since that was more or less the behavior I ultimately wanted – Duncan Jul 11 '13 at 15:41
0

So, it appears that the property type projection isn't working as you or I would expect it to. It's wrapping the GridLength property in an IReference<T> (or, in C#, Nullable<T>). Try binding to MyHeight.Value.

Nate Diamond
  • 5,525
  • 2
  • 31
  • 57
  • Hmm. Interestingly enough, I'm now getting this error with that modification: `Error: BindingExpression path error: 'Value' property not found on 'Windows.Foundation.IReference\`1'.` – Duncan Jul 06 '13 at 00:17
  • Ah! I found something interesting. Based on [this](http://www.charlespetzold.com/blog/2013/02/Cpp-Structures-and-Data-Bindings.html), c++ and C# `struct`s need some helper classes for interop. Check out the `GridLengthHelper` class [here](http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.gridlengthhelper.aspx). If it works, I'll edit the answer to reflect it. – Nate Diamond Jul 06 '13 at 00:51
  • Interesting, but I'm not sure that's the issue here. Petzold mentions that there are issues with binding to values that are not properties, which would be an issue if I was trying to bind to a member of the GridLength struct. But, since `MyHeight` is a property, I don't think this applies. Even if this was the case, I would be getting an error somewhere along the lines of "cannot find property" and not a conversion error. Additionally, I can properly bind to other value structs (such as `FontWeight`) – Duncan Jul 06 '13 at 06:06