トップ回答者
ListViewでデータにバインドしたCheckBoxを表示したとき、選択された項目のCheckBoxをクリックすると表示がおかしくなる

質問
-
INotifyPropertyChangedインターフェイスを使用して、ListViewに表示したCheckBoxにデータをバインドし、ListViewの項目をクリックする度にCheckBoxの表示が変更されるは確認できました。ところが、選択されている項目のCheckBoxをクリックすると表示が期待した動き(CheckからUncheck、またはその逆)にならず、元に戻って(Check→Uncheck→Check、または、Uncheck→Check→Uncheck)しまいます。
ちなみに、デバッガにてlistView_PreviewMouseDownの中にブレークポイントを張り、一度停止させてから続行すると期待した表示になります。
どう対処すればいいのかご教示頂けたら幸いです。
参考までに、コードは以下の通りです。
XAML
<ListView x:Name="listView" HorizontalAlignment="Left" Height="143" Margin="10,10,0,0" VerticalAlignment="Top" Width="139" ItemsSource="{Binding}" SelectionChanged="listView_SelectionChanged"> <ListView.View> <GridView> <GridViewColumn Header="チェック"> <GridViewColumn.CellTemplate> <DataTemplate> <CheckBox IsChecked="{Binding Path=Selected}" /> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Header="内 容" DisplayMemberBinding="{Binding Path=Comment}" /> </GridView> </ListView.View> <ListView.ItemContainerStyle> <Style TargetType="{x:Type ListViewItem}"> <EventSetter Event="PreviewMouseDown" Handler="listView_PreviewMouseDown" /> </Style> </ListView.ItemContainerStyle> </ListView>
C#
public ObservableCollection<MyData> myData = new ObservableCollection<MyData>(); public MainWindow() { InitializeComponent(); myData.Add(new MyData(true, "Sample1")); myData.Add(new MyData(false, "Sample2")); myData.Add(new MyData(true, "Sample3")); listView.DataContext = myData; } public class MyData : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public virtual void OnPropertyChanged(string name) { var h = PropertyChanged; if (h == null) return; h(this, new PropertyChangedEventArgs(name)); } private bool _Selected; public bool Selected { get { return _Selected; } set { _Selected = value; OnPropertyChanged("Selected"); } } private string _Comment; public string Comment { get { return _Comment; } set { _Comment = value; OnPropertyChanged("Comment"); } } public MyData (bool bBool, string sComment) { _Selected = bBool; _Comment = sComment; } } private void button_Click(object sender, RoutedEventArgs e) { MyData dd = sender as MyData; } private void listView_SelectionChanged(object sender, SelectionChangedEventArgs e) { ListView md = sender as ListView; MyData ss = (MyData)md.SelectedItem; ss.Selected = ss.Selected ? false : true; } private void listView_PreviewMouseDown(object sender, MouseButtonEventArgs e) { ListViewItem lvi = sender as ListViewItem; if (lvi == null) return; if (lvi.IsSelected) { MyData td = (MyData)lvi.Content; if (td != null) { td.Selected = td.Selected ? false : true; } } } }
- 編集済み tjshin 2015年12月10日 2:22
回答
-
簡単なのは
<CheckBox IsChecked="{Binding Path=Selected}" IsHitTestVisible="False" />
としてCheckBoxがマウスに反応しないようにしてしまうといいです
#ListViewのSelectionModeをSingle以外にしてると複数行選択で悲しいことに…
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
-
こんにちは。
PreviewMouseDownが処理された時は処理済みとしてマーク(e.Handled = true)してしまってはどうですか。
private void listView_PreviewMouseDown(object sender, MouseButtonEventArgs e) { ListViewItem lvi = sender as ListViewItem; if (lvi == null) return; if (lvi.IsSelected) { MyData td = (MyData)lvi.Content; if (td != null) { td.Selected = td.Selected ? false : true; e.Handled = true; } } }
- 回答としてマーク tjshin 2015年12月11日 7:43
すべての返信
-
簡単なのは
<CheckBox IsChecked="{Binding Path=Selected}" IsHitTestVisible="False" />
としてCheckBoxがマウスに反応しないようにしてしまうといいです
#ListViewのSelectionModeをSingle以外にしてると複数行選択で悲しいことに…
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
-
こんにちは。
PreviewMouseDownが処理された時は処理済みとしてマーク(e.Handled = true)してしまってはどうですか。
private void listView_PreviewMouseDown(object sender, MouseButtonEventArgs e) { ListViewItem lvi = sender as ListViewItem; if (lvi == null) return; if (lvi.IsSelected) { MyData td = (MyData)lvi.Content; if (td != null) { td.Selected = td.Selected ? false : true; e.Handled = true; } } }
- 回答としてマーク tjshin 2015年12月11日 7:43
-
そもそも、SelectionChangedイベントハンドラは要らないんじゃないかなぁ?
private void listView_PreviewMouseDown(object sender, MouseButtonEventArgs e) { ListViewItem lvi = sender as ListViewItem; if (lvi == null) return; var dc = (MyData)lvi.DataContext; dc.Selected = !dc.Selected; e.Handled = true; //if (lvi.IsSelected) //{ // MyData td = (MyData)lvi.Content; // if (td != null) // { // td.Selected = td.Selected ? false : true; // } //} }
#好みとしては、e.Handled = trueよりは、gekkaさんのIsHitTestVisible="False"が良いですね。 CheckBoxを表示専用にしてしまう方がわかりやすいので。★良い回答には回答済みマークを付けよう! MVP - .NET http://d.hatena.ne.jp/trapemiya/