Reputation: 47
My project is implemented in MVVM. I have a MainWindow, which consists of a statusbar and a tabview. Inside the tabview, there is a UserControl called "AnnotationView". Annotationview is the parent of two smaller usercontrols, called TimePicker. TimePicker consists of two textboxes, one for hours and one for minutes. I want to use this UserControl two times (that's also why I made it a Control of its own, to reuse it later on).
XAML of TimePicker:
<UserControl x:Class="archidb.Views.TimePicker"
x:Name="TimePickerControl"
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" Height="Auto" Width="Auto"
KeyboardNavigation.TabNavigation="Local">
<Grid DataContext="{Binding ElementName=TimePickerControl}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="5"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Style="{StaticResource TextBoxStyle}"
Text="{Binding Path=HourValue}"
x:Name="tbHours"
KeyboardNavigation.TabIndex="0"/>
<TextBlock Style="{StaticResource TextBlockStyle}"
Margin="0 -3 0 5"
Text=":"
Grid.Column="1"/>
<TextBox Grid.Column="2" Style="{StaticResource TextBoxStyle}"
Text="{Binding Path=MinuteValue}"
x:Name="tbMinutes"
KeyboardNavigation.TabIndex="1"/>
</Grid>
</UserControl>
TimePicker Code-Behind:
public partial class TimePicker : UserControl
{
public static readonly DependencyProperty HourValueProperty = DependencyProperty.Register("HourValue", typeof(string), typeof(TimePicker), new PropertyMetadata("00"));
public string HourValue
{
get { return (string)GetValue(HourValueProperty); }
set { SetValue(HourValueProperty, value); }
}
public static readonly DependencyProperty MinuteValueProperty = DependencyProperty.Register("MinuteValue", typeof(string), typeof(TimePicker), new PropertyMetadata("00"));
public string MinuteValue
{
get { return (string)GetValue(MinuteValueProperty); }
set { SetValue(MinuteValueProperty, value); }
}
public TimePicker()
{
InitializeComponent();
}
}
In the AnnotationControl, I insert the UserControls like this:
<v:TimePicker x:Name="tpStart"
HourValue="{Binding Path=StartHours}"
MinuteValue="{Binding Path=StartMinutes}"
KeyboardNavigation.TabIndex="2"/>
<v:TimePicker x:Name="tpEnde"
HourValue="{Binding Path=EndHours}"
MinuteValue="{Binding Path=EndMinutes}"
KeyboardNavigation.TabIndex="3"
Grid.Row="2"/>
DataContext of AnnotationControl is set to its viewmodel, where I declared the properties.
The problem is, the binding is not working. The default value I set in the dependency property ("00") is not showing in any of the textboxes. Also if I write something in the textboxes, the property in the viewmodel of AnnotationControl doesn't change its value. This problem has been bugging me for several days now, what am I doing wrong here?
Upvotes: 2
Views: 4746
Reputation: 69959
The solution is to simply use a RelativeSource Binding
in your UserControl
and to NOT set it's DataContext
to itself:
In your control:
<TextBox Style="{StaticResource TextBoxStyle}" Text="{Binding HourValue, RelativeSource=
{RelativeSource AncestorType={x:Type YourPrefixToBeAdded:TimePickerControl}}}"
x:Name="tbHours" KeyboardNavigation.TabIndex="0" />
<TextBlock Style="{StaticResource TextBlockStyle}" Margin="0 -3 0 5" Text=":"
Grid.Column="1" />
<TextBox Grid.Column="2" Style="{StaticResource TextBoxStyle}" Text="{Binding
MinuteValue, RelativeSource={RelativeSource AncestorType={x:Type
YourPrefixToBeAdded:TimePickerControl}}}" x:Name="tbMinutes"
KeyboardNavigation.TabIndex="1" />
Then you will be able to data bind the properties from outside the control.
Upvotes: 6
Reputation: 6222
Simplest way: Remove that line:
DataContext="{Binding ElementName=TimePickerControl}"
Bind like this:
"{Binding ElementName=TimePickerControl, Path=HourValue}"
Another way: (cleaner)
Set it in TimePicker constructor:
(this.Content as FrameworkElement).DataContext = this;
Bind like this:
"{Binding HourValue}"
After some reading, your example should be working so I assume you didn't implement INotifyPropertyChanged for your ViewModel, "00" is not shown because binding works, properties are set to default and their values are not updated.
Upvotes: 0
Reputation: 9713
Firstly, in the UserControl constructor, set the DataContext to itself:
public TimePicker()
{
InitializeComponent();
this.DataContext = this;
}
Also, remove this from your grid in the user control:
DataContext="{Binding ElementName=TimePickerControl}"
The DataContext of your user control has already been set within the user control itself, therefore when you use the following code:
HourValue="{Binding Path=EndHours}"
You are actually asking "Bind to EndHours in the UserControl's DataContext."
You need to change the binding so that it looks at the DataContext of the parent window. Give the parent window a name and use the following:
HourValue="{Binding DataContext.EndHours, ElementName=windowName}"
Upvotes: -1