WPF CommandParameter首先调用CanExecute为NULL [英] WPF CommandParameter is NULL first time CanExecute is called

查看:191
本文介绍了WPF CommandParameter首先调用CanExecute为NULL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到WPF和命令的问题,绑定到ItemsControl的DataTemplate内的一个Button。这种情况很简单。 ItemsControl绑定到一个对象列表,我想通过单击一个按钮可以删除列表中的每个对象。按钮执行命令,命令负责删除。 CommandParameter绑定到我要删除的对象。这样我就知道用户点击了什么。用户应该只能删除自己的对象 - 所以我需要在Command的CanExecute调用中进行一些检查,以验证用户是否拥有正确的权限。

I have run into an issue with WPF and Commands that are bound to a Button inside the DataTemplate of an ItemsControl. The scenario is quite straight forward. The ItemsControl is bound to a list of objects, and I want to be able to remove each object in the list by clicking a Button. The Button executes a Command, and the Command takes care of the deletion. The CommandParameter is bound to the Object I want to delete. That way I know what the user clicked. A user should only be able to delete their "own" objects - so I need to do some checks in the "CanExecute" call of the Command to verify that the user has the right permissions.

问题是传递给CanExecute的参数在第一次调用时为NULL,因此我无法运行启用/禁用命令的逻辑。但是,如果我启用它,然后单击按钮执行该命令,CommandParameter被正确传递。所以这意味着对CommandParameter的绑定是有效的。

The problem is that the parameter passed to CanExecute is NULL the first time it's called - so I can't run the logic to enable/disable the command. However, if I make it allways enabled, and then click the button to execute the command, the CommandParameter is passed in correctly. So that means that the binding against the CommandParameter is working.

ItemsControl和DataTemplate的XAML如下所示:

The XAML for the ItemsControl and the DataTemplate looks like this:

<ItemsControl 
    x:Name="commentsList"
    ItemsSource="{Binding Path=SharedDataItemPM.Comments}"
    Width="Auto" Height="Auto">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Button                             
                    Content="Delete"
                    FontSize="10"
                    Command="{Binding Path=DataContext.DeleteCommentCommand, ElementName=commentsList}" 
                    CommandParameter="{Binding}" />
            </StackPanel>                       
         </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

所以你可以看到我有一个注释对象的列表。我想要将DeleteCommentCommand的CommandParameter绑定到Command对象。

So as you can see I have a list of Comments objects. I want the CommandParameter of the DeleteCommentCommand to be bound to the Command object.

所以我想我的问题是:有没有人经历过这个问题? CanExecute在我的命令上被调用,但参数始终为NULL,为什么?

So I guess my question is: have anyone experienced this problem before? CanExecute gets called on my Command, but the parameter is always NULL the first time - why is that?

更新:我能够缩小问题下了一点。我添加了一个空的Debug ValueConverter,以便当CommandParameter是数据绑定时,我可以输出一个消息。原来的问题是CanExecute方法是在CommandParameter绑定到按钮之前执行的。我试图在Command之前设置CommandParameter(如建议) - 但它仍然不起作用。有关如何控制它的任何提示。

Update: I was able to narrow the problem down a little. I added an empty Debug ValueConverter so that I could output a message when the CommandParameter is data bound. Turns out the problem is that the CanExecute method is executed before the CommandParameter is bound to the button. I have tried to set the CommandParameter before the Command (like suggested) - but it still doesn't work. Any tips on how to control it.

Update2:有什么办法可以检测绑定是否完成,以便我可以强制重新评估命令?还有 - 这是一个问题,我有多个按钮(一个用于ItemsControl中的每个项目)绑定到同一个Command对象的实例?

Update2: Is there any way to detect when the binding is "done", so that I can force re-evaluation of the command? Also - is it a problem that I have multiple Buttons (one for each item in the ItemsControl) that bind to the same instance of a Command-object?

Update3:我已将我的SkyDrive的错误复制上传到: http://cid-1a08c11c407c0d8e.skydrive.live.com/self.aspx/Code%20samples/CommandParameterBinding.zip

Update3: I have uploaded a reproduction of the bug to my SkyDrive: http://cid-1a08c11c407c0d8e.skydrive.live.com/self.aspx/Code%20samples/CommandParameterBinding.zip

推荐答案

我偶然发现了类似的问题,并使用可信赖的TriggerConverter解决了这个问题。

I stumbled upon a similar problem and solved it using my trusty TriggerConverter.

public class TriggerConverter : IMultiValueConverter
{
    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // First value is target value.
        // All others are update triggers only.
        if (values.Length < 1) return Binding.DoNothing;
        return values[0];
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

值转换器采用任意数量的参数,并将第一个参数作为转换值传回。在您的情况下,在MultiBinding中使用时,如下所示。

This value converter takes any number of parameters and passes the first of them back as the converted value. When used in a MultiBinding in your case it looks like the following.

<ItemsControl 
    x:Name="commentsList"
    ItemsSource="{Binding Path=SharedDataItemPM.Comments}"
    Width="Auto" Height="Auto">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Button                             
                    Content="Delete"
                    FontSize="10"
                    CommandParameter="{Binding}">
                    <Button.Command>
                        <MultiBinding Converter="{StaticResource TriggerConverter}">
                            <Binding Path="DataContext.DeleteCommentCommand"
                                     ElementName="commentsList" />
                            <Binding />
                        </MultiBinding> 
                    </Button.Command>
                </Button>
            </StackPanel>                                       
         </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

您将不得不将TriggerConverter添加到某处,以使其工作。现在,Command属性的值在CommandParameter的值可用之前设置。甚至可以绑定到RelativeSource.Self和CommandParameter。达到同样的效果。

You will have to add TriggerConverter as a resource somewhere for this to work. Now the Command property is set not before the value for the CommandParameter has become available. You could even bind to RelativeSource.Self and CommandParameter instead of . to achieve the same effect.

这篇关于WPF CommandParameter首先调用CanExecute为NULL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆