2017-05-05 19 views
0

DataTemplateのバインディングを指定する正しい方法を探しています。DataTemplateでCommandとCommandParameterのバインド順序を設定する方法

Commandを正しく初期化するには、CommandParamterとCommandsのバインドの順序が関係します。

ここにxamlとその要点を示すソースコードがあります。 この例には4つのコマンドが含まれていますが、2は正しく初期化されないことが予想されます。 2は正しく初期化されるはずです。 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はInsideです。 両方ともバインディングの順序が同じです。ここで

は、デバッグ出力です:

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は予想通りcorretly初期化に失敗します。 CMD2期待通りに成功します。 CMD4はexpetedとして失敗します。 CMD3が失敗し、私はそれを期待していませんでした。

コマンドの前にCMD3のパラメータがバインドされなかったのはなぜですか?

DataTemplated Command/CommandParameterバインディングのxamlを記述する正しい方法は何ですか(コードに触れることはありません)。

答えて

0

この問題は、DataTemplateのコンテンツを独自のビューに入れることで解決できます。

使用

<DataTemplate> 
    <local:CommandView /> 
</DataTemplate> 

のCommandViewは、カスタムユーザーコントロールをbeeingてと。

<UserControl x:Class="WPFCommand.CommandView" 
      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" 
      xmlns:local="clr-namespace:WPFCommand" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <Button 
     CommandParameter="{Binding Parameter3}" 
     Command="{Binding CMD3}" 
     >Grid PAR->CMD</Button> 
</UserControl> 
関連する問題