F#でWPF --- リストボックスCommand --- 複数選択
下記記事にてリストボックスで利用できるBehaviorを作成しました。
F#でWPF --- リストボックスCommand - 何でもプログラミング
今回はこれを拡張して、複数選択に対応させた実装をします。
ListBoxBehavior
単選択の時とほとんど同じです。
SelectedItemを利用していたのをSelectedItemsに変更しました。
SelectedItemsにsetterはないので、AddやClearでコレクションを変更します。
open System.Collections open System.Windows.Input type Item(name : obj) = override this.ToString() = name.ToString() type ListBoxBehavior() = inherit BehaviorBase<ListBox>() static member val ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof<IEnumerable>, typeof<ListBoxBehavior>) member this.ItemsSource with get() = this.GetValue(ListBoxBehavior.ItemsSourceProperty) :?> IEnumerable and set(x:IEnumerable) = this.SetValue(ListBoxBehavior.ItemsSourceProperty, x) static member val SelectedIndicesProperty = DependencyProperty.Register("SelectedIndices", typeof<int list>, typeof<ListBoxBehavior>) member this.SelectedIndices with get() = this.GetValue(ListBoxBehavior.SelectedIndicesProperty) :?> int list and set(x:int list) = this.SetValue(ListBoxBehavior.SelectedIndicesProperty, x) static member val CommandProperty = DependencyProperty.Register("Command", typeof<ICommand>, typeof<ListBoxBehavior>) member this.Command with get() = this.GetValue(ListBoxBehavior.CommandProperty) :?> ICommand and set(x:ICommand) = this.SetValue(ListBoxBehavior.CommandProperty, x) override this.OnAttached control = let mutable items = [] let mutable isUpdatingFromVM = false let getSelectedIndices() = control.SelectedItems |> Seq.cast<Item> |> Seq.choose (fun x -> List.tryFindIndex ((=) x) items) |> Seq.toList let setSelectedItems indices = control.SelectedItems.Clear() indices |> List.choose (fun x -> List.tryItem x items) |> List.iter (control.SelectedItems.Add >> ignore) [ DependencyProperty.changed<IEnumerable> ListBoxBehavior.ItemsSourceProperty this |> Observable.subscribe (fun x -> isUpdatingFromVM <- true let indices = getSelectedIndices() items <- x |> Seq.cast<obj> |> Seq.toList |> List.map Item control.ItemsSource <- items setSelectedItems indices isUpdatingFromVM <- false) DependencyProperty.changed<int list> ListBoxBehavior.SelectedIndicesProperty this |> Observable.subscribe (fun x -> isUpdatingFromVM <- true setSelectedItems x isUpdatingFromVM <- false) control.SelectionChanged.Subscribe(fun _ -> if (not isUpdatingFromVM) && (this.Command <> null) then this.Command.Execute(getSelectedIndices())) ]
作成するアプリケーション
追加ボタンでリストが追加でき、削除ボタンで選択された複数のリストを削除できるアプリケーションです。
アプリケーションコード
こちらも単選択の時とほとんど同じです。
SelectedIndexをintからint listに変更しました。
リストボックスで複数選択を有効にするには、SelectionModeを変更します。
Extended | Ctrlクリック、Shiftクリックで複数選択 |
Multiple | クリックで複数選択 or 解除 |
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:local="clr-namespace:Behaviors;assembly=ListBoxBehavior" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="150" Width="200"> <Grid> <ListBox Margin="10,10,0,10" HorizontalAlignment="Left" Width="80" SelectionMode="Extended"> <i:Interaction.Behaviors> <local:ListBoxBehavior ItemsSource="{Binding Items}" SelectedIndices="{Binding SelectedIndices}" Command="{Binding SetSelectedIndices}" /> </i:Interaction.Behaviors> </ListBox> <Button Command="{Binding AddItem}" Content="追加" HorizontalAlignment="Left" Margin="95,10,0,0" VerticalAlignment="Top" Width="75"/> <Button Command="{Binding RemoveSelectedItems}" Content="削除" HorizontalAlignment="Left" Margin="95,35,0,0" VerticalAlignment="Top" Width="75"/> </Grid> </Window>
F#
open System open System.Windows type Msg = | AddItem | RemoveSelectedItems | SetSelectedIndices of int list type Model = { Items : string list SelectedIndices : int list } let initialModel = { Items = [] SelectedIndices = [] } let updateModel model msg = match msg with | AddItem -> { model with Items = "item" :: model.Items } | RemoveSelectedItems -> { model with Items = model.Items |> List.indexed |> List.filter (fun (i, _) -> List.contains i model.SelectedIndices |> not) |> List.map snd SelectedIndices = [] } | SetSelectedIndices x -> { model with SelectedIndices = x } [<STAThread>] [<EntryPoint>] let main argv = let window = Application.LoadComponent(Uri("MainWindow.xaml", UriKind.Relative)) :?> Window window.DataContext <- DataContext(initialModel, updateModel, id) Application().Run(window) |> ignore 0