带有命令属性的UserControl

时间:2014-06-02 11:24:38

标签: c# wpf icommand

我有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();
    }
}

现在,如果用户点击LinkLabel

,我想调用JumpCommand

因此我使用以下代码在MainWindow的视图中分配命令:

<view:JumpLabel LabelText="Extensions" JumpCommand="{Binding JumpLabelCommand, UpdateSourceTrigger=PropertyChanged}" CommandParameter="{Binding ElementName=control}"/>

在我的MainWindow的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中Command-Property的绑定问题。

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。如果我在DoJumpExecute中单击Button我的断点。如果我点击HyperLink未达到断点。

我仍然不理解......


解决方案

现在我在MainWindowView中使用以下代码

  <view:JumpLabel Grid.Row="1" JumpLabelText="My Jump Label" 
                        JumpCommand="{Binding DataContext.DoJumpCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
            RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"/>

现在可行。

3 个答案:

答案 0 :(得分:1)

根据您提供的代码判断,您可能遇到任何问题...假设您确实拥有正确定义的所有属性,这些是最可能的错误原因:

首先,当从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. 您的绑定视图模型中没有ICommand名为JumpLabelCommand的属性,或后面的代码。
  2. 您的视图中没有名为control的UI控件。
  3. 名为DataContext的UI控件的control没有合适的值可用作CommandParameter属性...也许这个Binding应该是:{ {1}}?
  4. 如果以上条件均不属实且您仍然遇到问题,请编辑您的问题并提供所有相关代码,其中应包含所有内容是相关的,例如。 CommandParameter="{Binding Propertyname, ElementName=control}"元素的详细信息,集control

答案 1 :(得分:1)

这是一个更普遍的答案:如果你创建一个带有依赖属性的usercontrol,那么你的绑定应该总是包含某种&#34;相对绑定&#34; - 我总是使用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的datacontext设置为self,那么您将断开继承的datacontext,这不是您想要的。所以你必须在你的用户控件中删除所有类型的datacontext设置为self。

updatesource触发器用于处理源的更新,这就是为什么你的updatesource触发器在你的usercontrol中没有任何意义。例如,文本块无法将Text属性更新为源 - 它可以使用文本框:)

答案 2 :(得分:-1)

你的JumpLabel Control的构造函数应该是

 public JumpLabel()
    {
        InitializeComponent();
        this.DataContext=new MainWindowViewModel();
    }