如何在DataTemplate for Command和CommandParameter中设置绑定顺序

时间:2017-05-05 15:58:51

标签: wpf xaml data-binding command datatemplate

我正在寻找指定DataTemplate绑定的正确方法。

为了正确初始化Command,它与CommandParamter和Commands绑定的顺序相关。

这是一个xaml和一些源代码来说明这一点。 该示例包含4个命令,2个预计不会正确初始化。 2应该正确初始化。 两个微不足道的案例表现如预期。 两个DataTemplate案例的行为与我的预期不同。

XAML:

<Window x:Class="WPFCommand.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPFCommand"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <Button 
            Command="{Binding CMD1}"
            CommandParameter="{Binding Parameter1}"
            >CMD->PAR</Button>
        <Button 
            CommandParameter="{Binding Parameter2}"
            Command="{Binding CMD2}"
            >PAR->CMD</Button>
        <DataGrid
            ItemsSource="{Binding DataGridItemsSource}"
            AutoGenerateColumns="False"
            HeadersVisibility="None"
            >
            <DataGrid.Columns >
                <DataGridTemplateColumn Width="1*">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button
                                Command="{Binding CMD4}"
                                CommandParameter="{Binding Parameter4}"
                                >Grid CMD->PAR</Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Width="1*">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button
                                CommandParameter="{Binding Parameter3}"
                                Command="{Binding CMD3}"
                                >Grid PAR->CMD</Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </StackPanel>
</Window>

代码隐藏

namespace WPFCommand
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Windows;
    using System.Windows.Input;

    public class DemoCommand : ICommand
    {
        bool? oldCanEx;
        private string myname;

        public DemoCommand(string myname)
        {
            this.myname = myname;
        }

        public event EventHandler CanExecuteChanged = delegate { };

        public bool CanExecute(object parameter)
        {
            bool newCanEx;
            if (parameter == null)
            {
                Debug.WriteLine($"{myname} CanExecute called with null");
                newCanEx = false;
            }
            else
            {
                Debug.WriteLine($"{myname} CanExecute called with {parameter}");
                newCanEx = true;
            }

            if (oldCanEx != newCanEx)
            {
                Debug.WriteLine($"{myname} CanExecute changed");
                oldCanEx = newCanEx;
                CanExecuteChanged(this, EventArgs.Empty);
            }
            return newCanEx;
        }

        public void Execute(object parameter)
        {
            Debug.WriteLine($"{myname} Execute {parameter}");
        }
    }

    public class Item
    {
        internal Item() { }
        public DemoCommand CMD3 { get; private set; } = new DemoCommand("CMD3");
        public DemoCommand CMD4 { get; private set; } = new DemoCommand("CMD4");
        public int Parameter3 { get; private set; } = 7;
        public int Parameter4 { get; private set; } = 13;
    }

    public class MainWindowViewModel
    {
        public IEnumerable<Item> DataGridItemsSource { get; private set; } = new List<Item> { new Item() };
        public DemoCommand CMD1 { get; private set; } = new DemoCommand("CMD1");
        public DemoCommand CMD2 { get; private set; } = new DemoCommand("CMD2");
        public int Parameter1 { get; private set; } = 42;
        public int Parameter2 { get; private set; } = 5;
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.DataContext = new MainWindowViewModel();
            InitializeComponent();
        }
    }
}

CMD1和CMD2在DataTemplate之外。 CMD3和CMD4都在里面。 两者在绑定的顺序上都表现出相同的差异。

这是Debug输出:

CMD1 CanExecute called with null
CMD1 CanExecute changed
CMD1 CanExecute called with null
CMD2 CanExecute called with 5
CMD2 CanExecute changed
CMD2 CanExecute called with 5
CMD4 CanExecute called with null
CMD4 CanExecute changed
CMD4 CanExecute called with null
CMD3 CanExecute called with null
CMD3 CanExecute changed
CMD3 CanExecute called with null

CMD1无法按预期正确初始化。 CMD2成功达成预期。 CMD4失败了。 CMD3失败,我没想到。

为什么CMD3的参数在命令之前没有绑定?

为DataTemplated命令/ CommandParameter绑定编写xaml的正确方法是什么(理想情况下不触及后面的代码)?

0 个答案:

没有答案