げんさん日記

プログラミングで気付いた事等を書きます。

DataGridのスクロールでイベントが勝手に発生する

2024年12月06日 10時57分40秒 | WPF
■現象 
DataGrid列のチェックボックスのUnCheckedイベントがスクロールするとイベント発生してしまう。
その為、Enabled指定をしたセルの状態が勝手に変わる。

●XAML
<DataGrid.Columns> 
    <DataGridTemplateColumn Header="使用" > 
        <DataGridTemplateColumn.CellTemplate> 
            <DataTemplate> 
                <CheckBox x:Name="SerialUseFlag" </div>
                          IsChecked="{Binding SerialUseFlagBool, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" 
                          Style="{StaticResource NormalCheckStyle}" 
                          > 
                    <i:Interaction.Triggers> 
                        <i:EventTrigger EventName="Checked"> 
                            <i:InvokeCommandAction Command="{Binding DataContext.UseCheckCommand, </div">
                                                                     RelativeSource={RelativeSource FindAncestor,  
                                                                                                AncestorType={x:Type DataGrid}}}" 
                                                   CommandParameter="true" 
                                                   /> 
                        </i:EventTrigger> 
                        <i:EventTrigger EventName="Unchecked"> 
                            <i:InvokeCommandAction Command="{Binding DataContext.UseCheckCommand, </div">
                                                                     RelativeSource={RelativeSource FindAncestor,  
                                                                                                AncestorType={x:Type DataGrid}}}"  
                                                   CommandParameter="false" 
                                                   /> 
                        </i:EventTrigger> 
                    </i:Interaction.Triggers> 
                </CheckBox> 
            </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
    </DataGridTemplateColumn> 
    <DataGridTemplateColumn Header="名称" > 
        <DataGridTemplateColumn.CellTemplate> 
            <DataTemplate> 
                <DockPanel HorizontalAlignment="Center" VerticalAlignment="Stretch"> 
                    <CheckBox IsChecked="{Binding HzSerialFlagBool," UpdateSourceTrigger="PropertyChanged," Mode="TwoWay}" </div>
                          IsEnabled="{Binding HzSerialFlagEnabled}" 
                          Style="{StaticResource NormalCheckStyle}" 
                          > 
                    </CheckBox> 
                </DockPanel> 
            </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
    </DataGridTemplateColumn> 
</DataGrid.Columns> 
使用チェックボックスの結果で名称チェックのEnableを切り替えているが、
スクロールするとEnableの設定が変わってしまう。 
 
■対応方法 
XamlでDataGridのScrollViewer.ScrollChangedをフックし、スクロールの場合はUncheckedイベントを無効にする。 
 
●Xaml
<DataGrid ItemsSource="{Binding SerialData}" </div>
          ScrollViewer.ScrollChanged="DataGrid_ScrollChanged" 
          >
ScrollViewer.ScrollChangedイベントを定義する。 
 
●コードビハインド 
       private void DataGrid_ScrollChanged(object sender, ScrollChangedEventArgs e) 
       { 
           // ViewModelのスクロールチェンジコマンドを実行する。 
           (this.DataContext as SerialPanelViewModel).SerialDataScrollChangedCommand.Execute(this); 
       } 
 
●ViewModel 
// チェックボックスイベント許可フラグ 
private bool IsAllowCheckBoxEvent { get; set; } = true;
  
// マウスダウン時、チェックボックスイベントの発生を許可する。 
private void OnSerialDataPreviewMouseDown() 
   this.IsAllowCheckBoxEvent = true; 
  
// スクロールチェンジ時、チェックボックスイベントの発生を不許可する。 
private void OnSerialDataScrollChanged() 
    this.IsAllowCheckBoxEvent = false; 
 
// チェック時、チェックボックスイベント許可フラグ=falseの時、処理を行わない。 
private void OnCheckUse(string mUseFlag) 
    if (this.IsAllowCheckBoxEvent == false) { return; } 
 
 


DataGridのCellTemplate内からViewModelにイベントを通知する。

2024年12月06日 08時10分54秒 | WPF
DataGridTemplateColumn内のコントロールからViewModelにコマンドを通知させます。


<DataGridTemplateColumn Header="使用" >
 <DataGridTemplateColumn.CellTemplate>
  <DataTemplate>
   <CheckBox x:Name="SerialUseFlag"
         IsChecked="{Binding ItemUseFlagBool}"
         Style="{StaticResource NormalCheckStyle}"
         >
    <i:Interaction.Triggers>
     <i:EventTrigger EventName="Checked">
      <i:InvokeCommandAction Command="{Binding DataContext.UseCheckCommand,
       RelativeSource={RelativeSource FindAncestor,
        AncestorType={x:Type DataGrid}}}"
       />
     </i:EventTrigger>
    </i:Interaction.Triggers>
   </CheckBox>
  </DataTemplate>
 </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

下のレベルからバインドする場合はRelativeSourceでコントロールに紐づいているDataContextから検索する必要があります。
この方法は他コントロールのテンプレートを作成した場合にも使用できます。






ViewのイベントをViewModelのコマンドで受け取る

2021年05月21日 12時47分44秒 | WPF
Viewで発生するイベントをViewModelのコマンドで受け取れるようにします。

プロジェクトの参照にSystem.Windows.Interactivityを追加します。

WindowにInteractivityを追加します。
<Window
  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
  >

WindowのContentRenderedをフックします。
<i:Interaction.Triggers>
 <i:EventTrigger EventName="ContentRendered">
  <i:InvokeCommandAction Command="{Binding LoadCommand}"/>
 </i:EventTrigger>
</i:Interaction.Triggers>

上記内容でViewのContentRenderedイベントをViewModelのLoadCommandコマンドで受け取れます。


ViewのコマンドをViewModelで受け取るCommandを作成する。

2021年05月21日 11時24分11秒 | WPF
Viewから発生したコマンドをViewModelで受け取れるようにします。

ICommandを継承したRelayCommandを作成します。
public sealed class RelayCommand : ICommand
{
}

実行するメソッドを保存するプロパティを定義します。
private Action ActionMethod { get; set; }

コンストラクタを定義します。
public RelayCommand(Action execute)
{
  this.ActionMethod = execute;
}

実行するか判断するメソッドを定義します。
public bool CanExecute(object parameter)
{
  // 全て実行する。
  return true;
}

実行するメソッドを定義します。
public void Execute(object parameter)
{
  this.ActionMethod();
}

ICommandの実行メソッドを定義します。
void ICommand.Execute(object parameter)
{
  this.Execute(parameter);
}

使用例
public sealed class MainViewModel : BaseViewModel
{
  // ロードコマンド
  public ICommand LoadCommand { get; private set; }

  // コンストラクタ
  public MainViewModel ()
  {
    // コマンドを作成する。
    this.LoadCommand = new RelayCommand(this.OnLoad);
  }

  //ロード
  public void OnLoad()
  {
  }
}


Viewとバインドするモデルのベースを作成する。

2021年05月20日 15時42分27秒 | WPF
Viewとバインドするモデルの共通処理をベースとして作成します。

クラスの名前をBaseBindableModelにしてBaseModelを継承します。
※BaseModelは記事『全モデルのベースを作成する。(IDisposable)』を参照
public abstract class BaseBindableModel : BaseModel
{
}

プロパティチェンジイベントを定義します。
public event PropertyChangedEventHandler PropertyChanged;

プロパティを保存するDictionaryを定義します。
private Dictionary PropertieItems { get; set; }

プロパティの変更通知メソッドを作成します。
public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
  if (this.PropertyChanged != null)
  {
   this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  }
}

GetメソッドとSetメソッドを作成します
※詳細は記事『ViewModelのバインディングプロパティを簡単に定義する。』を参考

使用例
Viewへの通知まで行ってくれます。
public Class TestBindableModel : BaseBindableModel
{
  public double Value
  {
   get { return base.Get<double>(); }
   set { base.Set(value); }
}