■現象
DataGrid列のチェックボックスのUnCheckedイベントがスクロールするとイベント発生してしまう。
その為、Enabled指定をしたセルの状態が勝手に変わる。
●XAML
<DataGrid.Columns>
その為、Enabled指定をしたセルの状態が勝手に変わる。
●XAML
<DataGrid.Columns>
<DataGridTemplateColumn Header="使用" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="SerialUseFlag" </div>
GetメソッドとSetメソッドを作成します。
使用例
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の設定が変わってしまう。
スクロールするとEnableの設定が変わってしまう。
■対応方法
XamlでDataGridのScrollViewer.ScrollChangedをフックし、スクロールの場合はUncheckedイベントを無効にする。
●Xaml
<DataGrid ItemsSource="{Binding SerialData}" </div>
<DataGrid ItemsSource="{Binding SerialData}" </div>
ScrollViewer.ScrollChanged="DataGrid_ScrollChanged"
>
ScrollViewer.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; }
}
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>
<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のコマンドで受け取れるようにします。
プロジェクトの参照にSystem.Windows.Interactivityを追加します。
WindowにInteractivityを追加します。
<Window
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
>
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>
<i:EventTrigger EventName="ContentRendered">
<i:InvokeCommandAction Command="{Binding LoadCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
上記内容でViewのContentRenderedイベントをViewModelのLoadCommandコマンドで受け取れます。
Viewから発生したコマンドをViewModelで受け取れるようにします。
ICommandを継承したRelayCommandを作成します。
public sealed class RelayCommand : ICommand
{
}
{
}
実行するメソッドを保存するプロパティを定義します。
private Action ActionMethod { get; set; }
コンストラクタを定義します。
public RelayCommand(Action execute)
{
this.ActionMethod = execute;
}
{
this.ActionMethod = execute;
}
実行するか判断するメソッドを定義します。
public bool CanExecute(object parameter)
{
// 全て実行する。
return true;
}
{
// 全て実行する。
return true;
}
実行するメソッドを定義します。
public void Execute(object parameter)
{
this.ActionMethod();
}
{
this.ActionMethod();
}
ICommandの実行メソッドを定義します。
void ICommand.Execute(object parameter)
{
this.Execute(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()
{
}
}
{
// ロードコマンド
public ICommand LoadCommand { get; private set; }
// コンストラクタ
public MainViewModel ()
{
// コマンドを作成する。
this.LoadCommand = new RelayCommand(this.OnLoad);
}
//ロード
public void OnLoad()
{
}
}
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));
}
}
{
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); }
}
{
public double Value
{
get { return base.Get<double>(); }
set { base.Set(value); }
}