简体   繁体   English

具有命令属性的UserControl

[英]UserControl with command-property

I have a UserControl for a LinkLabel with an Image before. 我以前有一个带有图像的LinkLabelUserControl

The XAML looks like: 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>

The DataContext of this UserControl is set to the CodeBehind-File. UserControl的DataContext设置为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 现在,如果用户单击LinkLabel我想调用JumpCommand

Therefor I use the following code to assign the Command in the view of my MainWindow: 为此,我使用以下代码在MainWindow的视图中分配Command:

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

In the ViewModel of my MainWindow I have: 在我的MainWindow的ViewModel中,我有:

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. 在DummyExecute中,我有一个从未达到的断点。 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 . 我创建了一个新的小项目,重点关注UserControl Command-Property的绑定问题。

The MainWindowView is: 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>

The MainWindowViewModel is: 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)
    {

    }
}

My UserControl is: 我的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>

The code-behind of the UserControl is 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); }
    }
}

In the MainWindowView the Command-Property of my UserControl and a Button are binded to the same ICommand . 在MainWindowView中,我的UserControl的Command-Property和一个Button绑定到相同的ICommand If I click the Button my Breakpoint in DoJumpExecute is reached. 如果我单击Button ,将达到DoJumpExecute中的断点。 If I click on the HyperLink the Breakpoint is not reached. 如果单击HyperLink ,则无法达到断点。

I still don't understand it... 我还是不明白...


Solution

In my MainWindowView now I use the following code 现在在我的MainWindowView中,使用以下代码

  <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. 首先,从UserControl XAML页面到其属性的数据绑定时,尽管它很冗长,但您应该习惯于使用RelativeSource Binding Note that you should do this instead of setting the UserControl.DataContext to its code behind: 请注意,您应该这样做, 而不是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>

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: 如果满足以下任何条件,那么这当然将不起作用:

  1. You don't have an ICommand property named JumpLabelCommand in your bound view model, or code behind. 您的绑定视图模型中没有名为JumpLabelCommandICommand属性,也没有后面的代码。
  2. You don't have a UI control named control in your view. 您的视图中没有名为control的UI控件。
  3. The 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}" ? UI控件( controlDataContext没有适合用作CommandParameter属性的值...也许此Binding应该是: 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. control元素的详细信息,例如DataContext等。

this is more a general answer: if you create a usercontrol with dependency properties then your binding should always contain some kind of "relative binding" - i always use elementname binding. 这是一个更通用的答案:如果您创建具有依赖项属性的用户控件,则您的绑定应始终包含某种“相对绑定”-我始终使用elementname绑定。 so your usercontrol binding should look like this. 因此您的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>

if you set the datacontext for your usercontrol to self, then you break the datacontext inheriting and that is not what you want. 如果将用户控件的datacontext设置为self,则将中断datacontext继承,而这不是您想要的。 so you have to remove all kinds of setting the datacontext to self within your usercontrol. 因此,您必须在用户控件中删除所有将datacontext设置为self的设置。

the updatesource trigger are used to handle the update to the source, thats why your updatesource trigger makes no sense in your usercontrol. updatesource触发器用于处理对源的更新,这就是为什么updatesource触发器在用户控件中毫无意义的原因。 eg a textblock cant updatethe Text property to source - it would work with a textbox :) 例如,文本块无法将Text属性更新为源-它可以与文本框一起使用:)

your constructor of JumpLabel Control should be 您的JumpLabel控件的构造函数应为

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM