views:

245

answers:

2

I am following a tutorial here. which shows a basic example on how to bind to a dependency property.

<Binding ElementName="This" Path="IPAddress" UpdateSourceTrigger="PropertyChanged">

where "This" is the name of the current window:

<Window x:Class="SOTCBindingValidation.Window1" x:Name="This"

whenever i try to do something like this, i keep getting the same error:

Cannot find source for binding with reference 'ElementName=GridControlControl1'. BindingExpression:Path=IPAddress; DataItem=null; target element is 'TextBox' (Name='AddressBox'); target property is 'Text' (type 'String')

my code:

 <UserControl x:Class="WpfGridtest.GridControl" x:Name="GridControlControl1" ... />

    <TextBox x:Name="AddressBox">
    <TextBox.Text>
        <Binding ElementName="GridControlControl1" Path="IPAddress"                 UpdateSourceTrigger="PropertyChanged">

        </Binding>
    </TextBox.Text>
</TextBox>

codebehind:

partial class GridControl : UserControl
     public static readonly DependencyProperty IPAddressProperty = DependencyProperty.Register("IPAddress", typeof(string), typeof(GridControl), new UIPropertyMetadata("1.1.1.1"));

        public string IPAddress
        {
            get { return (string)GetValue(IPAddressProperty); }
            set { SetValue(IPAddressProperty, value); }
        }

it's almost like something changed in .Net 4.0?

+1  A: 

Try using RelativeSource:

<TextBox>
  <TextBox.Text>
    <Binding Path="IPAddress">
      <Binding.RelativeSource>
        <RelativeSource
           Mode="FindAncestor"
           AncestorType="{x:Type UserControl}"
           AncestorLevel="1"
        />
      </Binding.RelativeSource>
    </Binding>
  </TextBox.Text>
</TextBox>

Instead of {x:Type UserControl}you could insert your actual type there, i.e.:

<TextBox>
  <TextBox.Text>
    <Binding Path="IPAddress">
      <Binding.RelativeSource>
        <RelativeSource xmlns:my="clr-namespace:WpfGridtest"
           Mode="FindAncestor"
           AncestorType="{x:Type my:GridControl}"
           AncestorLevel="1"
        />
      </Binding.RelativeSource>
    </Binding>
  </TextBox.Text>
</TextBox>
Andreas
Sorry for that it is rather hot here. Of course you need to use findancestor...
Andreas
thanks, i've actually tried seemingly every possible iteration of FindAncestor before resorting to DependecyProperty approach.. definitely x:Type CustomControl
Sonic Soul
Did it work now then? Or is there anything wrong with the FindAncestor approach?
Andreas
had no luck with FindAncestor. i wasted hours on friday with that approach. tried adding it to the top Window, as well as Control, referencing it as x:Type .. keep getting the same non informative error messages.. "unable to find ancestor blah blah"
Sonic Soul
When I'm at home later I will try to reproduce. Here I don't have an appropriate IDE (and even time) for testing. We should really be able to accomplish this... :) do not give up!
Andreas
i can't give up! have to finish my project somehow :)
Sonic Soul
It should've been UserControl... it was the heat, forgive me.
Andreas
+2  A: 

It depends on what you want. I'll try to offer a complete answer. One way to guarantee better success with this syntax is to use VS2010's XAML Binding Builder, which is how I assembled the syntax you're about to see.

If you want an element of the UserControl to display your IPAddress dependency property, (which looks like it's defined correctly to me), use this syntax within the body of the UserControl's markup:

   <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, 
                             AncestorType={x:Type my:GridControl}, 
                             AncestorLevel=1}, 
              Path=IPAddress}" />

Most XAML binding examples use this syntax rather than the more verbose hierarchical XML:

        <TextBlock>
            <TextBlock.Text>
                <Binding Path="IPAddress">
                    <Binding.RelativeSource>
                        <RelativeSource Mode="FindAncestor" 
                                        AncestorType="{x:Type my:GridControl}"
                                        AncestorLevel="1" 
                        />
                    </Binding.RelativeSource>
                </Binding>
            </TextBlock.Text>
        </TextBlock>

...but both kinds of syntax produce the same results. Note here that the AncestorType is the class name of your UserControl, not the x:Name you would supply when using the UserControl in other markup.

Suppose you have a UI element in markup outside your UserControl, and you want access to your DependencyProperty for that other control. The markup looks something like this:

    <my:GridControl 
       x:Name="GridControl1" IPAddress="192.168.1.1" />
    <TextBox Text="{Binding ElementName=GridControl1, Path=IPAddress}"/>

Or, alternatively, this:

    <TextBox>
        <TextBox.Text>
            <Binding ElementName="GridControl1" Path="IPAddress"/>
        </TextBox.Text>
    </TextBox>

Note here that this time you're using the x:Name property of the GridControl rather than the class name, and that you refer to it as an ElementName, and not an "Ancestor". In both cases, though, the Path is the declared name of the DependencyProperty you defined.

Rob Perkins
thank you. although it is the same thing me and Andreas have already, but i appreciate your post, and xaml builder link.
Sonic Soul
You're welcome. Binding syntax is tough; it only gets evaluated at runtime and the errors are nearly impossible to interpret, in my opinion.About the only thing I can think of other than my general answer is that there is a missing right-bracket character after `Path=IPAddress`, but the XAML editor would have caught that right away...That, and I used "FrameworkPropertyMetadata" rather than "UIPropertyMetadata" to set up the DP, but I don't think that's a difference with a distinction either.
Rob Perkins