Visual Studio / WPF > ListBoxの選択を解除する > 自作クラスのbfSelected プロパティ=falseではListBoxのSelectedItemsが残ったまま


動作環境
Windows 7 Pro (32bit)
Microsoft Visual Studio 2017 Community

http://gushwell.ldblog.jp/archives/52333865.html
を元に学習中。

リンク先ではListBoxアイテムの選択処理をしている。

選択したアイテムを解除する処理を実装してみた。

  • Button追加: B_clear
  • B_clearClick()処理実装
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
// 
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace _170608_t1523_listBoxMultiSelect
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var myList = (this.DataContext as MyDataList);
            myList.UpdateSelectedItems();
        }

        private void B_clearClick(object sender, RoutedEventArgs e)
        {
            var myList = (this.DataContext as MyDataList);
            // 1. 以下ではListBoxの選択状態が残ったままになった
            //foreach (var elem in myList)
            //{
            //    elem.bfSelected = false;
            //}
            //myList.UpdateSelectedItems();

            // 2. 以下ではListBoxの選択状態がクリアされる
            listBox1.SelectedItems.Clear();
            myList.UpdateSelectedItems();
        }
    }

    public class MyData
    {
        public string Name { get; set; }
        public Nullable<bool> bfSelected { get; set; }
    }

    public class MyDataList : ObservableCollection<MyData>
    {
        private int lastYear = 2016;

        public MyDataList()
        {
            AddNewItem();
            AddNewItem();
            AddNewItem();
            AddNewItem();
        }
        public void AddNewItem()
        {
            var data = new MyData { Name = string.Format("{0}年", lastYear) };
            this.Add(data);
            lastYear++;
        }

        public List<MyData> SelectedItems { get; private set; }

        public void UpdateSelectedItems()
        {
            var lnq = Items.Where(
                x => x.bfSelected.HasValue &&
                (x.bfSelected.Value == true));
            SelectedItems = new List<MyData>(lnq);
            this.OnPropertyChanged(new PropertyChangedEventArgs("SelectedItems"));
        }
    }
}
MainWindow.xaml
<Window x:Class="_170608_t1523_listBoxMultiSelect.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:_170608_t1523_listBoxMultiSelect"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MyDataList/>
    </Window.DataContext>
    <Window.Resources>
        <Style x:Key="listBoxItemStyle" TargetType="{x:Type ListBoxItem}">
            <Setter Property="IsSelected" Value="{Binding bfSelected}"/>
        </Style>
    </Window.Resources>
    <StackPanel>
        <Button x:Name="B_clear"  
                Height="28" Width="100" HorizontalAlignment="Left"
                Content="ClearSelection"
                Click="B_clearClick"
                />
        <Grid VerticalAlignment="Stretch" Height="280">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <ListBox Name="listBox1"
                 SelectionMode="Multiple"
                 ItemsSource="{Binding}" 
                 DisplayMemberPath="Name"
                 ItemContainerStyle="{StaticResource listBoxItemStyle}"
                 SelectionChanged="listBox1_SelectionChanged"/>
            <ListBox Name="listBox2"
                 Grid.Column="1"
                 ItemsSource="{Binding SelectedItems}" 
                 DisplayMemberPath="Name"/>
        </Grid>
    </StackPanel>
</Window>

選択時

Clear Selection押下後

code snippet

        private void B_clearClick(object sender, RoutedEventArgs e)
        {
            var myList = (this.DataContext as MyDataList);
            // 1. 以下ではListBoxの選択状態が残ったままになった
            //foreach (var elem in myList)
            //{
            //    elem.bfSelected = false;
            //}
            //myList.UpdateSelectedItems();

            // 2. 以下ではListBoxの選択状態がクリアされる
            listBox1.SelectedItems.Clear();
            myList.UpdateSelectedItems();
        }

上記において1の処理ではDataContextのmyList要素のbfSelectedはfalseになり、右側のListBoxの表示はクリアされた。
一方で、左側のlistBox1のSelectedItemsは残ったままだった。
(次回選択時に残っていたSelectedItemsも選択状態になった。)

2の処理ではlistBox1のSelectedItemsもクリアされた。
listBox1を直接指定している点はいいのかどうか。Bindingだけで処理できる方が良いようには思う。