WPF databinding error in Tag property
Asked Answered
R

3

3
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:son"
         x:Class="son.SonWindow">
    <Grid x:Name="myGrid">
        <Grid.Tag>
            <Label Content="{Binding ActualWidth, ElementName=myGrid}" />
        </Grid.Tag>
    </Grid>
</UserControl>

Just as a simple code above, but the binding cannot find the Element myGrid. During runtime, the error is shown in the Output window

"System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=myGrid'. BindingExpression:Path=ActualWidth; DataItem=null; target element is 'Label' (Name=''); target property is 'Content' (type 'Object')"

I am using Visual Studio 2015 community version with .Net Framework 4.5.2. Any ideas? Thank you in advance.

Richy answered 1/10, 2015 at 3:15 Comment(2)
Why are you wrapping a Label inside the Tag property? If you move the Label element outside the Tag it works.Blackpoll
@Blackpoll ya.. I understand that just removing the tag will make it work, but I am wondering why the above code will generate a Error. I just want to figure out whether the error is related to something special of the Tag property.Richy
S
27

The element (whose property is bound) should be part of the visual tree so that the visual tree search can be done. When using Binding with ElementName or RelativeSource, it performs some internal visual tree search. But in your code the Label is disconnected from visual tree by the Tag. Label is just an object in memory, referenced by the Tag property.

Since .NET 4.0 you can use the {x:Reference} markup instead, like this:

<Grid.Tag>
    <Label Content="{Binding ActualWidth, Source={x:Reference myGrid}}" />
</Grid.Tag>

Edit:

Using {x:Reference} can cause issue of cyclic dependency if the reference name points to some element containing the {x:Reference}. In your case it is myGrid (containing {x:Reference}). So it cannot be used in your case. Instead you need to use some proxy. This technique seems a bit hacky but in fact it's very pretty. It also surely works in any version of .NET (supporting WPF):

<Grid x:Name="myGrid">
    <Grid.Resources>
        <DiscreteObjectKeyFrame x:Key="proxy" Value="{Binding ElementName=myGrid}"/>
    </Grid.Resources>
    <Grid.Tag>
        <Label Content="{Binding Value.ActualWidth, Source={StaticResource proxy}}" />
    </Grid.Tag>
</Grid>

As you see the Binding works with its Source set to StaticResource pointing to a DiscreteObjectKeyFrame. This is a Freezable object so it's quite interesting that all Bindings set for any DependencyProperty of a Freezable object work well no matter you use ElementName or RelativeSource. So we bind its Value property to the Grid (with name of myGrid). Later on we bind the Content property of Label to the Freezable object but with Path set to Value.ActualWidth (Value points to Grid, so we need to append ActualWidth to bind it to Grid.ActualWidth).

In fact you can use any Freezable object but we use DiscreteObjectKeyFrame for convenience, its Value accepts all kinds of object.

There is another technique to set Binding in a situation like this (disconnected context) but it requires you to create a custom MarkupExtension. It's of course more complicated (but still simple enough once you're familiar with WPF).

Stroud answered 1/10, 2015 at 3:51 Comment(6)
Thank you for your kind help. I replace my code with yours. However, during design time, I got an error object reference not set to an instance of an object. And during run time, an exception is shown in the Output window.Richy
The exception is Exception thrown: 'System.Windows.Markup.XamlParseException' in PresentationFramework.dll An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll Additional information: Cannot call MarkupExtension.ProvideValue because of a cyclical dependency. Properties inside a MarkupExtension cannot reference objects that reference the result of the MarkupExtension. The affected MarkupExtensions are: 'System.Windows.Data.Binding' Line number '7' and line position '20'.Richy
@JuniverHazoic sorry, I did not notice the cyclic issue, please see my edit for another solution.Stroud
Fantastic solution!!! Thank you very much. I think now I have a better understanding of visual tree and get a workaround to deal with similar scenarios as above.Richy
Fantastic in the sense that it helped me; not at all fantastic in the sense that I went through many iterations and about 2 hours trying to figure out how to add a friggin tooltip. This proves xaml is an anti-pattern. No presentation system should ever be this over-complicated.Revell
This little bit saved me..."{Binding ElementName=MyGrid}". There are other solutions but they all assume "{Binding}" will do the trick. None of them worked for me. Thanks so much....Helbonnas
B
0

I tried below code snippet in WPF and its working fine.

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid x:Name="myGrid">
    <Grid.Tag>
        <Label Content="{Binding ActualWidth, ElementName=myGrid}" />
    </Grid.Tag>
</Grid>

Birdt answered 1/10, 2015 at 3:47 Comment(3)
this code looks exactly like the OP's, so you should provide some info about your environment, such as version of .NET, how did you know it works? The only reason this could work is in the latest version of .NET it may behave differently (improved). At least in .NET 4.5 (and earlier versions) this won't work.Stroud
i tried your code snippet in WPF, but during runtime the Output window again give the same error as above.Richy
I tested this in VS2010 WPF application (.Net Framework 4.0). I am able to see window without any binding errors when I ran my application.Birdt
P
0

I have also try to replicate issue but below code is working fine in VS 2010.

<Window x:Class="CustomEventHandlerClick.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CustomEventHandlerClick"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid x:Name="myGrid">
        <Grid.Tag>
            <Label Content="{Binding ActualWidth, ElementName=myGrid}"/>
        </Grid.Tag>
    </Grid>
   </Grid>

Paediatrics answered 1/10, 2015 at 6:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.