带有命令属性的用户控件
本文关键字:用户 控件 属性 命令 | 更新日期: 2023-09-27 18:06:09
我有一个UserControl
的LinkLabel
之前的图像。
XAML看起来像:
<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>
此UserControl
的DataContext设置为CodeBehind-File。
Code-Behind-File看起来像:
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();
}
}
现在我想调用JumpCommand,如果用户点击LinkLabel
因此,我使用以下代码在主窗口视图中分配命令:
<view:JumpLabel LabelText="Extensions" JumpCommand="{Binding JumpLabelCommand, UpdateSourceTrigger=PropertyChanged}" CommandParameter="{Binding ElementName=control}"/>
在我的主窗口的ViewModel我有:
private ICommand _jumpLabelCommand;
public ICommand JumpLabelCommand
{
get { return _jumpLabelCommand; }
set
{
_jumpLabelCommand = value;
OnPropertyChanged();
}
}
和
public MainWindowViewModel()
{
_mainWindowModel = new MainWindowModel();
JumpLabelCommand = new RelayCommand(DummyExecute);
}
private void DummyExecute(object parameter)
{
}
在DummyExecute中,我有一个永远不会到达的断点。我不明白为什么我的命令不起作用。我做错了什么?
更新:
我创建了一个新的小项目,重点关注UserControl
命令属性的绑定问题。
MainWindowView是:
<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>
MainWindowViewModel是:
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)
{
}
}
我的UserControl
是:
<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>
UserControl
的代码背后是
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); }
}
}
在MainWindowView中,我的UserControl
和Button
的命令属性绑定到相同的ICommand
。如果我点击Button
我的断点在DoJumpExecute到达。如果我单击HyperLink
,则未达到断点。
我还是不明白…
<
解决方案/strong>
在我的MainWindowView现在我使用以下代码
<view:JumpLabel Grid.Row="1" JumpLabelText="My Jump Label"
JumpCommand="{Binding DataContext.DoJumpCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"/>
根据您提供的代码判断,您可能会遇到许多问题…假设您实际上已经正确定义了正在使用的所有属性,这些是最有可能导致错误的原因:
首先,当数据从UserControl
XAML页面绑定到它的属性时,您应该习惯使用RelativeSource Binding
,尽管它很冗长。注意,您应该使用而不是将UserControl.DataContext
设置为其后面的代码:
<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>
接下来,有这行代码:
<view:JumpLabel LabelText="Extensions" JumpCommand="{Binding JumpLabelCommand,
UpdateSourceTrigger=PropertyChanged}" CommandParameter="{Binding ElementName=
control}" />
如果下列任何一个条件为真,这当然不能工作:
- 你没有一个名为
JumpLabelCommand
的ICommand
属性在你的绑定视图模型中,或者代码后面。 - 你的视图中没有一个名为
control
的UI控件。 - 名为
control
的UI控件的DataContext
没有合适的值用作CommandParameter
属性…也许Binding
应该是:CommandParameter="{Binding Propertyname, ElementName=control}"
?
如果以上条件都不成立,而您仍然有问题,那么请编辑您的问题并提供所有相关代码,其中应包括所有相关的代码,例如。control
元素的详细信息,它设置为DataContext
,等等
这是一个更一般的答案:如果你创建一个带有依赖属性的用户控件,那么你的绑定应该总是包含某种"相对绑定"——我总是使用elementname绑定。所以你的usercontrol绑定应该是这样的。
<UserControl x:Name="uc">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Source={x:Static helper:ImageHelper.JumpLabelImage}}" Width="16" Height="16" VerticalAlignment="Center"/>
<TextBlock >
<Hyperlink Command="{Binding ElementName=uc, Path=JumpCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
CommandParameter="{Binding ElementName=uc, Path=CommandParameter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<TextBlock Text="{Binding ElementName=uc, Path=LabelText, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" VerticalAlignment="Center" />
</Hyperlink>
</TextBlock>
</StackPanel>
</UserControl>
如果您将usercontrol的数据上下文设置为self,那么您就破坏了数据上下文的继承,这不是您想要的。所以你必须移除所有在你的usercontrol中设置datacontext为self的方法。
updatesource触发器用于处理对源的更新,这就是为什么你的updatesource触发器在你的usercontrol中没有意义。例如,一个文本块不能更新文本属性的来源-它将工作与文本框:)
你的JumpLabel Control的构造函数应该是
public JumpLabel()
{
InitializeComponent();
this.DataContext=new MainWindowViewModel();
}