I'm trying to implement a UserControl
which hosts other controls which are bound to certain properties of it. In my case it'd display a Slider next to a NumericUpDown
- both controls would be bound to the UserControl
's Value
property. My approach would be defining a DependencyProperty
for each control so when using this control, properties like Minimum
, TickPlacement
etc. can still be changed by setting a new slider as value for the corresponding property:
<!-- Displays a slider with default properties next to a text block-->
<Foo/>
<!-- Displays a sider with custom properties -->
<Foo>
<Foo.Slider>
<Slider Maximum="500" TickPlacement="Both" TickFrequency="20"/>
</Foo.Slider>
</Foo>
The code-behind looks like this:
public partial class Foo : UserControl
{
public Foo()
{
InitializeComponent();
Slider = new Slider();
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(double), typeof(Foo), new PropertyMetadata(0.0));
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public static readonly DependencyProperty SliderProperty = DependencyProperty.Register(nameof(Slider), typeof(Slider), typeof(Foo),
new PropertyMetadata(
new PropertyChangedCallback((obj, e) =>
{
Slider slNew = (Slider)e.NewValue;
if (slNew == null)
obj.SetValue(SliderProperty, new Slider());
else
slNew.SetBinding(ValueProperty,
new Binding("Value")
{
Source = obj,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
Mode = BindingMode.TwoWay
});
})));
public Slider Slider
{
get => (Slider)GetValue(SliderProperty);
set => SetValue(SliderProperty, value ?? new Slider());
}
}
The relevant part of the XAML code looks like this:
<UserControl x:Name="ctrlBase" [...]>
<Grid [...]>
<Grid.ColumnDefinitions [...]/>
<ContentControl DataContext="{Binding ElementName=ctrlBase}"
Content="{Binding Path=Slider}"/>
<!-- NumericUpDown to be implemented -->
<TextBlock Grid.Column="1"
Text="{Binding ElementName=ctrlBase, Path=Value}/>
</Grid>
</UserControl>
The actual problem is that the binding created from code-behind doesn't seem to work. I assume this due to the following:
Value
property from XAML changes
the value displayed by the text block but not the slider's value.You're using the wrong ValueProperty
. It should be the one of the Slider class, not Foo.ValueProperty
:
slNew.SetBinding(Slider.ValueProperty, new Binding("Value") { ... });
It would have worked if you had used Slider.ValueProperty.AddOwner
instead of DependencyProperty.Register
.
That said, a simpler approach would probably be to simply declare a Slider in your UserControl's XAML and provide a default Slider Style in the Foo Resources during instantiation:
<Foo ...>
<Foo.Resources>
<Style TargetType="Slider">
...
</Style>
</Foo.Resources>
</Foo>