Binding a UserControl property to its child via ElementName results a binding error
I have the following XAML:
<UserControl x:Class="WpfWindow.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.RenderTransform>
<TranslateTransform X="{Binding ElementName=MySlider, Path=ActualWidth}" />
</UserControl.RenderTransform>
<Grid>
<Slider x:Name="MySlider" Canvas.Left="41" Canvas.Top="86" Height="23" Width="100" Minimum="0" Maximum="100"/>
</Grid>
</UserControl>
When I try to use a window with the UserControl inside I get:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName开发者_JS百科=MySlider'. BindingExpression:Path=ActualWidth; DataItem=null; target element is 'TranslateTransform' (HashCode=53368240); target property is 'X' (type 'Double')
It is especially strange since using the same code directly in a Window works flawlessly.
For now I've resolved the issue by setting the binding in code, however, I have no idea why my version doesn't work and I'd rather have everything in XAML if possible.
Thanks!
I've noticed that sometimes when setting Bindings with ElementName on Window
/UserControl
etc. the order of declaration is important. I'm not sure of the reason for this but if you declare the Grid
before you set <UserControl.RenderTransform>
I think it'll work
<UserControl ...>
<Grid Background="Red">
<Slider x:Name="MySlider" Canvas.Left="41" Canvas.Top="86" Height="23" Width="100" Minimum="0" Maximum="100"/>
</Grid>
<UserControl.RenderTransform>
<TranslateTransform X="{Binding ElementName=MySlider, Path=ActualWidth}" />
</UserControl.RenderTransform>
</UserControl>
I actually have sort of similar issue and would like to share my solution.
I have set of shaders, which I want to apply to the borders. Shader's properties binded to the control's values (slider value).
XAML:
<Window.Resources>
<ResourceDictionary>
<Shaders:BrightnessContrastEffect x:Key="brightnessContrastEffect" Contrast="{Binding ElementName=SliderContrast, Path=Value}" Brightness="{Binding ElementName=SliderBrightness, Path=Value}" />
<Shaders:SaturationHueEffect x:Key="saturationHueEffect" Hue="{Binding ElementName=SliderHue, Path=Value}" Saturation="{Binding ElementName=SliderSaturation, Path=Value}"/>
<Shaders:SharpenEffect x:Key="sharpenEffect" Amount="{Binding ElementName=SliderSharpen, Path=Value}" />
</ResourceDictionary>
</Window.Resources>
...
<StackPanel Name="PanelImage" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" SizeChanged="PanelImage_SizeChanged">
<Border Effect="{StaticResource brightnessContrastEffect}">
<Border Effect="{StaticResource saturationHueEffect}">
<Border Effect="{StaticResource sharpenEffect}">
<Border Name="PanelShaderInvert">
<Viewbox Stretch="Fill" MinHeight="400" MinWidth="640">
<dz:MultiScaleImage Name="ImageViolation" MinHeight="400" MinWidth="640"
Source="{Binding ElementName=MyPath, Path=Content}"
MouseLeftButtonDown="ImageViolationMouseLeftButtonDown"
MouseLeftButtonUp="ImageViolationMouseLeftButtonUp"
MouseRightButtonUp="ImageViolationMouseRightButtonUp" MouseMove="ImageViolation_MouseMove" />
</Viewbox>
</Border>
</Border>
</Border>
</Border>
</StackPanel>
<GridSplitter HorizontalAlignment="Right" VerticalAlignment="Stretch" Grid.Column="1" ResizeBehavior="PreviousAndNext" Width="0" />
<StackPanel Grid.Column="2" Grid.Row="0" Height="250" VerticalAlignment="Top">
<Label Content="Brightness:" Style="{StaticResource DoubleLineLayoutLabel}" />
<telerik:RadSlider Name="SliderBrightness" Minimum="-1" Maximum="1" Value="0" Margin="8,0" LargeChange="0.4" SmallChange="0.4" TabIndex="1" />
<Label Content="Contrast:" Style="{StaticResource DoubleLineLayoutLabel}" />
<telerik:RadSlider Name="SliderContrast" Maximum="2" Value="1" Margin="8,0" LargeChange="0.4" SmallChange="0.4" TabIndex="2" />
<Label Content="Hue:" Style="{StaticResource DoubleLineLayoutLabel}" />
<telerik:RadSlider Name="SliderHue" Maximum="359" Margin="8,0" LargeChange="72" SmallChange="72" TabIndex="3" />
<Label Content="Saturation:" Style="{StaticResource DoubleLineLayoutLabel}" />
<telerik:RadSlider Name="SliderSaturation" Maximum="5" Value="1" Margin="8,0" LargeChange="1" SmallChange="1" TabIndex="4" />
<Label Content="Sharpen:" Style="{StaticResource DoubleLineLayoutLabel}" />
<telerik:RadSlider Name="SliderSharpen" Maximum="2" Value="0" Margin="8,0" LargeChange="0.4" SmallChange="0.4" TabIndex="5" />
<CheckBox Name="CheckBoxInvertColours" Content="Invert Colours" Margin="8" Checked="CheckBoxInvertColoursChecked" Unchecked="CheckBoxInvertColoursUnchecked" TabIndex="6" />
</StackPanel>
Works perfectly while in Window, but after I moved that XAML to the User Control it just stop working.
You cannot move Window.Resources to the bottom of the user control.
So, solution, which works for me was to assign resources right in the container (Border in my case) instead of referencing them from the Resource section:
<StackPanel Name="PanelImage" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" SizeChanged="PanelImage_SizeChanged">
<Border>
<Border.Effect>
<Shaders:BrightnessContrastEffect Contrast="{Binding ElementName=SliderContrast, Path=Value}" Brightness="{Binding ElementName=SliderBrightness, Path=Value}" />
</Border.Effect>
<Border>
<Border.Effect>
<Shaders:SaturationHueEffect Hue="{Binding ElementName=SliderHue, Path=Value}" Saturation="{Binding ElementName=SliderSaturation, Path=Value}"/>
</Border.Effect>
<Border>
<Border.Effect>
<Shaders:SharpenEffect Amount="{Binding ElementName=SliderSharpen, Path=Value}" />
</Border.Effect>
<Border Name="PanelShaderInvert">
<Viewbox Stretch="Fill" MinHeight="400" MinWidth="640">
<dz:MultiScaleImage Name="ImageViolation" MinHeight="400" MinWidth="640"
Source="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:ImageControl, AncestorLevel=1}, Path=ImageSource}"
MouseLeftButtonDown="ImageViolationMouseLeftButtonDown"
MouseLeftButtonUp="ImageViolationMouseLeftButtonUp"
MouseRightButtonUp="ImageViolationMouseRightButtonUp" MouseMove="ImageViolation_MouseMove" />
</Viewbox>
</Border>
</Border>
</Border>
</Border>
</StackPanel>
<GridSplitter HorizontalAlignment="Right" VerticalAlignment="Stretch" Grid.Column="1" ResizeBehavior="PreviousAndNext" Width="0" />
<StackPanel Grid.Column="2" Grid.Row="0" Height="250" VerticalAlignment="Top">
<Label Content="Brightness:" Style="{StaticResource DoubleLineLayoutLabel}" />
<telerik:RadSlider Name="SliderBrightness" Minimum="-1" Maximum="1" Value="0" Margin="8,0" LargeChange="0.4" SmallChange="0.4" TabIndex="1" />
<Label Content="Contrast:" Style="{StaticResource DoubleLineLayoutLabel}" />
<telerik:RadSlider Name="SliderContrast" Maximum="2" Value="1" Margin="8,0" LargeChange="0.4" SmallChange="0.4" TabIndex="2" />
<Label Content="Hue:" Style="{StaticResource DoubleLineLayoutLabel}" />
<telerik:RadSlider Name="SliderHue" Maximum="359" Margin="8,0" LargeChange="72" SmallChange="72" TabIndex="3" />
<Label Content="Saturation:" Style="{StaticResource DoubleLineLayoutLabel}" />
<telerik:RadSlider Name="SliderSaturation" Maximum="5" Value="1" Margin="8,0" LargeChange="1" SmallChange="1" TabIndex="4" />
<Label Content="Sharpen:" Style="{StaticResource DoubleLineLayoutLabel}" />
<telerik:RadSlider Name="SliderSharpen" Maximum="2" Value="0" Margin="8,0" LargeChange="0.4" SmallChange="0.4" TabIndex="5" />
<CheckBox Name="CheckBoxInvertColours" Content="Invert Colours" Margin="8" Checked="CheckBoxInvertColoursChecked" Unchecked="CheckBoxInvertColoursUnchecked" TabIndex="6" />
</StackPanel>
I believe this is a bug, but at least there is workaround.
精彩评论