Reputation: 330
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 MyCustomType
is 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.
Upvotes: 1
Views: 685
Reputation: 6289
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}}}"
For testing, I removed use of Tuple
as it's not needed, so the collection is defined as ObservableCollection<PercentageOrFixed>
Upvotes: 2