I am creating an UserControl with 2 RepeatButtons and one TextBox. So problems begin when i want to Bind some properties....
FYI i am using Caliburn.micro as Framework..
i need to have the value of property Interval from the parent to define the time lapse of both repeat button
i need to have the MaxValue defined in the parent and use it in the event MouseClick of customcontrol
i need to initialize the value of TextBox of custom control from parent, use it in the event mouseclick of custom control to obtain the new value update the TextBox and use the new value changed in the parent...
what i have tested:
CustomRepeatButton.xaml.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace ChromiumWPF.UserControls
{
public partial class CustomRepeatButton : UserControl
{
public CustomRepeatButton()
{
InitializeComponent();
}
public string TextValue
{
get { return (string)GetValue(TextValueProperty); }
set { SetValue(TextValueProperty, value); }
}
public static DependencyProperty TextValueProperty =
DependencyProperty.Register("TextValue", typeof(string), typeof(CustomRepeatButton));
public int IntervalValue
{
get { return (int)GetValue(IntervalValueProperty); }
set { SetValue(IntervalValueProperty, value); }
}
public static DependencyProperty IntervalValueProperty =
DependencyProperty.Register("IntervalValue",
typeof(int),
typeof(CustomRepeatButton),
new FrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
);
public int MaxValue
{
get { return (int)GetValue(MaxValueProperty); }
set { SetValue(MaxValueProperty, value); }
}
public static DependencyProperty MaxValueProperty =
DependencyProperty.Register("MaxValue", typeof(int), typeof(CustomRepeatButton));
:
:
//same definition for ResetValue, MinValue and IncrementValue
private void RepeatButton_Click(object sender, RoutedEventArgs e)
{
// click on button + or - and change the value of TextValue i trap in usercontrol Parent
var RB = sender as RepeatButton;
}
}
}
CustomRepeatButton.xaml (see Bindings TextValue and IntervalValue in Style)
<UserControl x:Class="ChromiumWPF.UserControls.CustomRepeatButton"
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"
xmlns:local="clr-namespace:ChromiumWPF.UserControls"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<Style TargetType="TextBox">
<Style.Setters>
<Setter Property="FontFamily" Value="Consolas"/>
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="IsReadOnly" Value="True"/>
<Setter Property="IsEnabled" Value="True"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="Background" Value="Aquamarine"/>
<Setter Property="Text" Value="{Binding TextValue, Mode=TwoWay}"/>
</Style.Setters>
</Style>
<Style TargetType="RepeatButton">
<Style.Setters>
<Setter Property="Interval" Value="{Binding IntervalValue, Mode=TwoWay}"/>
<Setter Property="Background" Value="Gray"/>
<EventSetter Event="Click" Handler="RepeatButton_Click"/>
</Style.Setters>
</Style>
</UserControl.Resources>
<Grid>
<StackPanel Orientation="Horizontal">
<RepeatButton Content="-" />
<TextBox />
<RepeatButton Content="+" />
</StackPanel>
</Grid>
</UserControl>
ChromeViewModel.cs
private string adress;
public string Adress
{
get { return adress; }
set
{
adress = value;
NotifyOfPropertyChange(() => Adress);
}
}
private int _test;
public int Test
{
get { return _test; }
set
{
_test = value;
NotifyOfPropertyChange(() => Test);
}
}
private int _maxV;
public int MaxV
{
get { return _maxV; }
set
{
_maxV = value;
NotifyOfPropertyChange(() => MaxV);
}
}
ChromeView.xaml
<UserControl x:Class="ChromiumWPF.Views.ChromeView"
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"
xmlns:cal="http://www.caliburnproject.org"
xmlns:uc="clr-namespace:ChromiumWPF.UserControls"
xmlns:local="clr-namespace:ChromiumWPF.Views"
xmlns:vm="clr-namespace:ChromiumWPF.ViewModels"
mc:Ignorable="d" d:DataContext="{d:DesignInstance Type=vm:ChromeViewModel}"
d:DesignHeight="800" d:DesignWidth="1200">
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Vertical" VerticalAlignment="Top"
HorizontalAlignment="Center">
<ComboBox x:Name="Months" Background="Aqua" Height="30" Width="100"
VerticalContentAlignment="Center"/>
<uc:CustomRepeatButton TextValue="{Binding Adress}"
IncrementValue="10"
IntervalValue="{Binding Test}"
MaxValue="{Binding MaxV}"
MinValue="900"
ResetValue="1080" />
</StackPanel>
</Grid>
</UserControl>
So i have problem with Test, Adress and MaxV (only Bindings in relation with the customControl).
I dont see why the bindings is in error, the definition of DP and properties seems ok for me?? is it a problem of DataContext? Maybe i have to set the DataContext to ChromeViewModel? if yes how i could do that?... Thanks for help..
errors displayed:
System.Windows.Data Error: 40 : BindingExpression path error: 'Adress' property not found on 'object' ''CustomRepeatButton' (Name='')'. BindingExpression:Path=Adress; DataItem='CustomRepeatButton' (Name=''); target element is 'CustomRepeatButton' (Name=''); target property is 'TextValue' (type 'String')
System.Windows.Data Error: 40 : BindingExpression path error: 'Test' property not found on 'object' ''CustomRepeatButton' (Name='')'. BindingExpression:Path=Test; DataItem='CustomRepeatButton' (Name=''); target element is 'CustomRepeatButton' (Name=''); target property is 'IntervalValue' (type 'Int32')
System.Windows.Data Error: 40 : BindingExpression path error: 'MaxV' property not found on 'object' ''CustomRepeatButton' (Name='')'. BindingExpression:Path=MaxV; DataItem='CustomRepeatButton' (Name=''); target element is 'CustomRepeatButton' (Name=''); target property is 'MaxValue' (type 'Int32')
In WPF the dependency property system uses value precedence. For example, the
DataContextvalue of aFrameworkElementis implicitly inherited from the parent. If you set the value explicitly you will override the inherited value (the parent'sDataContextwill be ignored by the property system).In general you want a custom control to inherit the parents
DataContextso that external data bindings assigned to the dependency properties.The external
Bindinguses the currentDataContextas source (implicitly):The following local
Bindingoverrides the inheritedDataContextvalue (taken from your code):Because of this
Binding, theDataContextofCustomRepeatButtonis theCustomRepeatButtoncontrol itself. EveryBindingthat uses the implicit binding syntax ({Binding path}) will now bind to theCustomRepeatButton. This explains the error message that states that the source object is of typeCustomRepeatButton: "BindingExpression path error: 'Adress' property not found on 'object' ''CustomRepeatButton'".This also exemplifies why you should never set the
DataContextof a custom control explicitly - unless you want to surprise the user of your control.To fix this don't ever set the
DataContextof custom control explicitly. In order to bind the internals to the control's properties you must use the proper binding source i.e explicit binding source.If the internals are assigned to the
Contentproperty of aContentControl, for example of aUserControl, you must useBinding.RelativeSourceand set theRelativeSource.AncestorTypeproperty of theRelativeSourceextension:Bindings are the same when defined in a
Style:If the internals are defined inside a
ControlTemplate, you would have to use theTemplateBindingextension (instead ofBinding) or use theBindingextension and set theBinding.RelativeSourceproperty using theRelativeSourceextension and set itsRelativeSource.Modeproperty toRelativeSourceMode.TemplatedParent: