Reputation: 53
I got a strange issue with binding in XAML
with Element Name
.
Everything worked just fine but when I surrounded controls and usercontrols with a StackPanel
I get a Binding Error.
I'm binding the visibility of two usercontrols with the IsChecked Property of two togglebuttons (IsDeadToggle and IsNotTransportable) and using ElementName.
<ItemsControl AlternationCount="100" FocusVisualStyle="{x:Null}" HorizontalAlignment="Left">
<ItemsControl.ItemsSource>
<CompositeCollection>
<StackPanel x:Name="FirstSP" Margin="0,0,10,0">
<TextBlock FocusVisualStyle="{x:Null}"
Style="{StaticResource WrapTitleAddTextBlock}"
Text="{x:Static languages:ResCommon.General}" />
<StackPanel x:Name="BuggedSP" Background="{StaticResource WrapBackground}">
<StackPanel Orientation="Horizontal"
Margin="10,20">
<RadioButton Content="{x:Static languages:ResCommon.Man}"
IsChecked="{Binding Path=Add.Presenter.Customer.Gender, Mode=TwoWay, Converter={StaticResource EnumMatchToBooleanConverter}, ConverterParameter=Male}" />
<RadioButton x:Name="IsWoman"
Content="{x:Static languages:ResCommon.Woman}"
IsChecked="{Binding Path=Add.Presenter.Customer.Gender,
Mode=TwoWay,
Converter={StaticResource EnumMatchToBooleanConverter},
ConverterParameter=Female}" />
</StackPanel>
<formElement:LabelComboBox Margin="{StaticResource ControlAddMargin}"
Visibility="{Binding Add.Presenter.Customer.CustomerIdInsured, Converter={StaticResource NullToVisibilityConverter}}"
LabelName="{x:Static languages:ResCommon.BeneficiaryType}"
ComboBoxDisplayMemberItem="Translation"
ComboBoxSelectedValueItem="Enum"
ComboBoxItems="{Binding Source={me:EnumValues EnumType=entities:TypeOfBeneficiary, ResourceName='Languages.ResEnum,Languages'}}"
ComboBoxSelectedItem="{Binding Add.Presenter.Customer.TypeOfBeneficiary}" />
<formElement:InnerLabelBox Margin="{StaticResource ControlAddMargin}"
LabelName="{x:Static languages:ResCommon.LastName}"
TextBoxValue="{Binding Add.Presenter.Customer.LastName,
Converter={StaticResource StringToUpperStringConverter},
Mode=TwoWay,
ValidatesOnDataErrors=true,
NotifyOnValidationError=true}" />
<formElement:LabelBox Margin="{StaticResource ControlAddMargin}"
LabelName="{x:Static languages:ResCommon.MaidenName}"
TextBoxValue="{Binding Add.Presenter.Customer.MaidenName,
Converter={StaticResource StringToUpperStringConverter},
Mode=TwoWay,
ValidatesOnDataErrors=true,
NotifyOnValidationError=true}"
Visibility="{Binding IsChecked,
ElementName=IsWoman,
Converter={StaticResource BooleanToVisibilityConverter}}" />
<formElement:InnerLabelBox Margin="{StaticResource ControlAddMargin}"
LabelName="{x:Static languages:ResCommon.FirstName}"
TextBoxValue="{Binding Add.Presenter.Customer.FirstName,
Converter={StaticResource StringToCapitalizeStringConverter},
Mode=TwoWay,
ValidatesOnDataErrors=true,
NotifyOnValidationError=true}" />
<resources:DateTimePickerTextBoxSwitch
Margin="{StaticResource ControlAddMargin}"
TextBoxValue="{Binding Add.Presenter.Customer.BirthDateCustom,
Mode=TwoWay,
ValidatesOnDataErrors=true,
NotifyOnValidationError=true}"
DateTimeValue="{Binding Add.Presenter.Customer.BirthDate, Mode=TwoWay}" />
<Grid Width="220" Margin="10,10,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="60"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Style="{StaticResource DarkSmallFontStyle}" Text="{x:Static languages:ResCustomers.IsDead}"></TextBlock>
<ToggleButton Grid.Column="1" IsChecked="{Binding Add.Presenter.Customer.IsAlive, Mode=TwoWay}"
Style="{StaticResource OnOffToggleButton}"
x:Name="IsDeadToggle" />
</Grid>
<formElement:LabelDatePicker Margin="{StaticResource ControlAddMargin}"
DatePickerValue="{Binding Add.Presenter.Customer.DeathDate,
Mode=TwoWay}"
LabelName="{x:Static languages:ResCustomers.DeathDate}"
Visibility="{Binding IsChecked,
ElementName=IsDeadToggle,
Converter={StaticResource BooleanToVisibilityConverterCustomInvert}}"
PrintEnum="WithDate" />
<Grid Width="220" Margin="10,10,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="60"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Style="{StaticResource DarkSmallFontStyle}" Text="{x:Static languages:ResCustomers.IsNoTransportable}"></TextBlock>
<ToggleButton Grid.Column="1" IsChecked="{Binding Add.Presenter.Customer.IsNoTransportable, Mode=TwoWay}"
Style="{StaticResource OnOffToggleButton}"
x:Name="IsNotTransportableToggle" />
</Grid>
<formElement:MultiLineTextBox
Margin="{StaticResource ControlAddMargin}"
LabelName="{x:Static languages:ResCustomers.NoTransportComment}"
TextBoxValue="{Binding Add.Presenter.Customer.NoTransportComment,
Mode=TwoWay,
ValidatesOnDataErrors=true,
NotifyOnValidationError=true}"
Visibility="{Binding IsChecked,
ElementName=IsNotTransportableToggle,
Converter={StaticResource BooleanToVisibilityConverterCustom}}" />
</StackPanel>
</StackPanel>
The added StackPanel is the one withthe following property
x:name="BuggedSP"
Error:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=IsDeadToggle'. BindingExpression:Path=IsChecked; DataItem=null; target element is 'LabelDatePicker' (Name='UCLabelDatePicker'); target property is 'Visibility' (type 'Visibility')
EDIT 1 :
If I delete the FirstSP StackPanel it works again... I begin to think it's a depth issue. But I can't see why my binding wouldn't work at a specific depth level
EDIT 2 :
If I delete the grids surrounding the togglebuttons, it doesn't work either so it doesn't matter if the toggle is at the same level as the usercontrol.
So with that VisualTree (WPF Tree WPF Tree Visualizer) everything's just fine:
<WrapPanel>
<ItemsControl>
<ItemsPresenter>
<WrapPanel>
<StackPanel>
<!-- List of UC and Toggles-->
With this one it doesn't work:
<WrapPanel>
<ItemsControl>
<ItemsPresenter>
<WrapPanel>
<StackPanel>
<StackPanel x:Name="BuggedSp">
<!-- List of UC and Toggles-->
Upvotes: 2
Views: 491
Reputation: 319
I can see that your ToggleButton
, IsDeadToggle
, has a two way binding on the IsChecked
property to the Add.Presenter.Customer.IsAlive
property on your data context.
I can also see that you are trying to bind the Visibility
property of your LabelDatePicker
to the IsChecked
property of the ToggleButton
, using a converter to inverse and then convert the bool value to a System.Windows.Visibility
.
Since both the ToggleButton
and LabelDatePicker
share the same data context, I would simply bind the visibility of the LabelDatePicker
to the same property on the data context:
<formElement:LabelDatePicker
Margin="{StaticResource ControlAddMargin}"
DatePickerValue="{Binding Add.Presenter.Customer.DeathDate, Mode=TwoWay}"
LabelName="{x:Static languages:ResCustomers.DeathDate}"
Visibility="{Binding Add.Presenter.Customer.IsAlive, Converter={StaticResource BooleanToVisibilityConverterCustomInvert}}"
PrintEnum="WithDate" />
Note: the data context (Customer
object) will need to implement System.ComponentModel.INotifyPropertyChanged
and the IsAlive
property will need to raise the PropertyChanged
event with the name of the property to ensure the LabelDatePicker
is properly notified to rebind when the IsDeadToggle
check box has changed its value.
See MSDN for more info: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx
As a rule, I tend to avoid element-to-element binding in favour of a common property in the data context. This way is more testable and less brittle (as if you change the name of the source element, IsDeadToggle
, then you need to remember to update the binding target).
Upvotes: 0