带有命令属性的用户控件

本文关键字:用户 控件 属性 命令 | 更新日期: 2023-09-27 18:06:09

我有一个UserControlLinkLabel之前的图像。

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中,我的UserControlButton的命令属性绑定到相同的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}" />

如果下列任何一个条件为真,这当然不能工作:

  1. 你没有一个名为JumpLabelCommandICommand属性在你的绑定视图模型中,或者代码后面。
  2. 你的视图中没有一个名为control的UI控件。
  3. 名为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();
    }