I have a UserControl
for a LinkLabel
with an Image before.
The XAML looks like:
<UserControl>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Source={x:Static helper:ImageHelper.JumpLabelImage}}" Width="16" Height="16" VerticalAlignment="Center"/>
<TextBlock >
<Hyperlink Command="{Binding JumpCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
CommandParameter="{Binding CommandParameter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<TextBlock Text="{Binding LabelText, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" VerticalAlignment="Center" />
</Hyperlink>
</TextBlock>
</StackPanel>
</UserControl>
The DataContext of this UserControl
is set to the CodeBehind-File.
The Code-Behind-File looks like:
public partial class JumpLabel : UserControl
{
public static readonly DependencyProperty LabelTextProperty = DependencyProperty.Register("LabelText", typeof(string), typeof(JumpLabel));
public static readonly DependencyProperty JumpCommandProperty = DependencyProperty.Register("JumpCommand", typeof(ICommand), typeof(JumpLabel));
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(JumpLabel));
public string LabelText
{
get { return (string)GetValue(LabelTextProperty); }
set { SetValue(LabelTextProperty, value); }
}
public ICommand JumpCommand
{
get { return (ICommand)GetValue(JumpCommandProperty); }
set { SetValue(JumpCommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public JumpLabel()
{
InitializeComponent();
}
}
Now I want to call the JumpCommand if the user clicks on the LinkLabel
Therefor I use the following code to assign the Command in the view of my MainWindow:
<view:JumpLabel LabelText="Extensions" JumpCommand="{Binding JumpLabelCommand, UpdateSourceTrigger=PropertyChanged}" CommandParameter="{Binding ElementName=control}"/>
In the ViewModel of my MainWindow I have:
private ICommand _jumpLabelCommand;
public ICommand JumpLabelCommand
{
get { return _jumpLabelCommand; }
set
{
_jumpLabelCommand = value;
OnPropertyChanged();
}
}
and
public MainWindowViewModel()
{
_mainWindowModel = new MainWindowModel();
JumpLabelCommand = new RelayCommand(DummyExecute);
}
private void DummyExecute(object parameter)
{
}
In the DummyExecute I have a Breakpoint which is never reached. I'm not getting it why my Command doesn't work. What am I doing wrong?
Update:
I've created a new small project with focus on the binding-problem for the Command-Property in the UserControl
.
The MainWindowView is:
<Window x:Class="UCWithDP.View.MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clr-namespace:UCWithDP.ViewModel"
xmlns:view="clr-namespace:UCWithDP.View"
Title="MainWindowView" Height="300" Width="600">
<Window.DataContext>
<viewModel:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="{Binding SomeText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<view:JumpLabel Grid.Row="1" JumpLabelText="My Jump Label" JumpCommand="{Binding DoJumpCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Grid.Row="2" Content="Some Button" Command="{Binding DoJumpCommand}"/>
</Grid>
</Window>
The MainWindowViewModel is:
internal class MainWindowViewModel : ViewModelBase
{
private string _someText;
private ICommand doJumpCommand;
public MainWindowViewModel()
{
SomeText = "Hello from ViewModel";
DoJumpCommand = new RelayCommand(DoJumpExecute);
}
public string SomeText
{
get { return _someText; }
set
{
_someText = value;
OnPropertyChanged();
}
}
public ICommand DoJumpCommand
{
get { return doJumpCommand; }
set
{
doJumpCommand = value;
OnPropertyChanged();
}
}
private void DoJumpExecute(object parameter)
{
}
}
My UserControl
is:
<UserControl x:Class="UCWithDP.View.JumpLabel"
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" Height="20"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
x:Name="uc">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="X" FontWeight="Bold" VerticalAlignment="Center" Margin="2"/>
<TextBlock Grid.Column="1" Margin="2">
<Hyperlink Command="{Binding ElementName=uc, Path=JumpCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBlock Text="{Binding JumpLabelText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center"/>
</Hyperlink>
</TextBlock>
</Grid>
</UserControl>
The code-behind of the UserControl
is
public partial class JumpLabel : UserControl
{
public static readonly DependencyProperty JumpLabelTextProperty = DependencyProperty.Register(
"JumpLabelText", typeof (string), typeof (JumpLabel), new PropertyMetadata(default(string)));
public static readonly DependencyProperty JumpCommandProperty = DependencyProperty.Register(
"JumpCommand", typeof (ICommand), typeof (JumpLabel), new PropertyMetadata(default(ICommand)));
public JumpLabel()
{
InitializeComponent();
}
public ICommand JumpCommand
{
get { return (ICommand) GetValue(JumpCommandProperty); }
set { SetValue(JumpCommandProperty, value); }
}
public string JumpLabelText
{
get { return (string) GetValue(JumpLabelTextProperty); }
set { SetValue(JumpLabelTextProperty, value); }
}
}
In the MainWindowView the Command-Property of my UserControl
and a Button
are binded to the same ICommand
. If I click the Button
my Breakpoint in DoJumpExecute is reached. If I click on the HyperLink
the Breakpoint is not reached.
I still don't understand it...
Solution
In my MainWindowView now I use the following code
<view:JumpLabel Grid.Row="1" JumpLabelText="My Jump Label"
JumpCommand="{Binding DataContext.DoJumpCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"/>
and now it works.
Judging by the code that you have provided, you could have any number of problems... assuming that you actually have all of the properties that you are using correctly defined, these are the most likely causes of error:
Firstly, when data binding from a UserControl
XAML page to its properties, you should get used to using the RelativeSource Binding
, despite its verbosity. Note that you should do this instead of setting the UserControl.DataContext
to its code behind:
<Hyperlink Command="{Binding JumpCommand, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" CommandParameter="{Binding CommandParameter,
RelativeSource={RelativeSource AncestorType={x:Type YourPrefix:YourUserControl}},
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBlock Text="{Binding LabelText, RelativeSource={RelativeSource AncestorType={
x:Type YourPrefix:YourUserControl}, UpdateSourceTrigger=PropertyChanged,
Mode=TwoWay}" VerticalAlignment="Center" />
</Hyperlink>
Next, you have this line of code:
<view:JumpLabel LabelText="Extensions" JumpCommand="{Binding JumpLabelCommand,
UpdateSourceTrigger=PropertyChanged}" CommandParameter="{Binding ElementName=
control}" />
This will of course not work if any of the following conditions are true:
ICommand
property named JumpLabelCommand
in your bound view model, or code behind.control
in your view.DataContext
of the UI control named control
does not have a suitable value to use as the CommandParameter
property... perhaps this Binding
should have been: CommandParameter="{Binding Propertyname, ElementName=control}"
?If none of the above conditions are true and you are still having problems, then please edit your question and provide all of the relevant code, which should include everything that is relevant, eg. details of the control
element, it's set DataContext
, etc.