首次调用CanExecute时,WPF CommandParameter为NULL [英] WPF CommandParameter is NULL first time CanExecute is called

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

问题描述

我遇到了一个问题,WPF和命令绑定到一个Button在一个ItemsControl的DataTemplate。这种情况非常简单。 ItemsControl绑定到一个对象列表,我想要能够通过单击一个按钮删除列表中的每个对象。按钮执行一个命令,命令负责删除。 CommandParameter绑定到我要删除的对象。这样我知道用户点击了什么。用户应该只能删除其自己的对象 - 所以我需要在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,因此我无法运行该逻辑来启用/禁用该命令。但是,如果我让它allways启用,然后单击按钮执行命令,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>

因此你可以看到我有一个Comments对象的列表。我想把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?

更新:

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.

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

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