Question

Well I created my first custom control with two dependency properties. One is a decimal and the other one has a CustomType of my own. So to test it I created a small project with only a window and tried to bind to it by using the Window itself as the data context like this:

<somethin:mycontrol MyDependencyProperty="{Binding MyCustomType}"/>

Where MyCustomTypeis a Property in MainWindow.cs and this did not work. So I made a guess and gave the MainWindow a name and then specified the Element name and it worked like this:

<Window x:Class="BC.WPF.TestArea.MainWindow" ... x:Name="MyWindow">
...
      <somethin:mycontrol MyDependencyProperty="{Binding ElementName=MyWindow, Path=MyCustomType}"/>

....
</Window>

So in my experience the ElementName part shouldn't be necessary but it was working so I was satisfied until I tried using it in an ItemsControl. Then things got really weird. First I tried this:

<ItemsControl ItemsSource="{Binding ElementName=MyWindow, Path=ObservableMyCustomTypes }">
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="somehting:CustomType" >
            <StackPanel Orientation="Horizontal" >
                <Label Content="{Binding Name }"/>
                <somethin:mycontrol  MyDependencyProperty="{Binding}" />
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

The strange thing here is that CustomType has a Name property and the Binding to Content in the label works but MyDependencyProperty="{Binding}" doesn't. I also tried MyDependencyProperty="{Binding .}" without success so just out of curiosity I tried putting elements of type Tuple<CustomType> in the collection instead and then binded to Item1 like this:

<ItemsControl ItemsSource="{Binding ElementName=MyWindow, Path=ObservableMyCustomTypes }">
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="system:Tuple" >
            <StackPanel Orientation="Horizontal" >
                <Label Content="{Binding Item1.Name }"/>
                <somethin:mycontrol  MyDependencyProperty="{Binding Item1}" />
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

And the incredible thing is that the Binding in the label to Item1.Name works but the other binding doesn't which really puzzles me because now I really don't see what could be wrong with the path but the one with ElementName=MyWindow works as expected.

What is going on?

Here is a link to a zip with the complete test project if you are curious.

Was it helpful?

Solution

First you break DataContext inheritance in your control by setting DataContext = this; in the constructor of your PercentageOrFixControl, so the expression

PercentageOrFixed="{Binding }"

is returning the control itself and not the PercentageOrFixed item that is in the collection. The data context for the label is the item of the collection and that's why it finds the Name property.

After removing the setter for data context from constructor, inner bindings in the control break since they look for properties on the control. Add

, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}

to the end of all bindings. For example, the IsChecked property of the first RadioButton should look like this:

IsChecked="{Binding UseFix, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"

Edit

For testing, I removed use of Tuple as it's not needed, so the collection is defined as ObservableCollection<PercentageOrFixed>

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top