概要
開閉するコントロールなら何でもいいですが、ここでは複数のExpanderがあるとします。
これらを同時に1つしか開かせないようにするとを実現します。
下のような感じですね。
そんなにわらわら並べないでTabでいいじゃんとかNavigation Railでいいじゃんとかは…まあそうですね。
前提
ReactivePropertyを使います。
Bindingを簡単にするというのもありますが、Pairwiseがあるのでこれを利用します。
実装
IReactivePrpoerty<bool>の配列等を受け取ってストリームに変換し、
trueの数が2以上になったら古い方のtrueをfalseに戻してやるような購読を行います。
Ext.cs
usingReactive.Bindings;usingReactive.Bindings.Extensions;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Reactive.Linq;namespaceAllowOnlyOneOpen.Extensions{publicstaticclassExt{publicstaticIDisposableAllowOnlyOneTrue(thisIEnumerable<IReactiveProperty<bool>>source)=>source.CombineLatest().Pairwise().Where(x=>x.NewItem.SkipWhile(n=>!n).Skip(1).Any(n=>n))// コントロールの個数を考えるとCount()を素直に使ってよさそうですね.Subscribe(p=>p.OldItem.Select((v,i)=>(v,i)).Where(x=>x.v).Select(x=>source.ElementAt(x.i).Value=false).ToList());}}
View
ただExpanderが4つ並んでいるだけです。MaterialDesignThemeは見栄えのためだけです。
MainWindow.xml
<Windowx:Class="AllowOnlyOneOpen.Views.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:md="http://materialdesigninxaml.net/winfx/xaml/themes"xmlns:vm="clr-namespace:AllowOnlyOneOpen.ViewModels"Title="MainWindow"Width="400"Height="440"d:DataContext="{d:DesignInstance Type=vm:MainWindowViewModel,
IsDesignTimeCreatable=True}"Foreground="{StaticResource MaterialDesignDarkForeground}"Background="{StaticResource MaterialDesignDarkBackground}"mc:Ignorable="d"><StackPanel><ExpanderHeader="A"IsExpanded="{Binding AIsExpanded.Value, Mode=TwoWay}"><RectangleHeight="100"Fill="Cyan"/></Expander><ExpanderHeader="B"IsExpanded="{Binding BIsExpanded.Value, Mode=TwoWay}"><RectangleHeight="100"Fill="Gray"/></Expander><ExpanderHeader="C"IsExpanded="{Binding CIsExpanded.Value, Mode=TwoWay}"><RectangleHeight="100"Fill="LightGreen"/></Expander><ExpanderHeader="D"IsExpanded="{Binding DIsExpanded.Value, Mode=TwoWay}"><RectangleHeight="100"Fill="Violet"/></Expander></StackPanel></Window>
ViewModel
ViewにBindしているものを配列に放り込んで、先ほど作った拡張メソッドを使います。
MainWindowViewModel.cs
usingAllowOnlyOneOpen.Extensions;usingReactive.Bindings;namespaceAllowOnlyOneOpen.ViewModels{publicclassMainWindowViewModel:ViewModelBase{publicReactivePropertySlim<bool>AIsExpanded{get;}=new();publicReactivePropertySlim<bool>BIsExpanded{get;}=new();publicReactivePropertySlim<bool>CIsExpanded{get;}=new();publicReactivePropertySlim<bool>DIsExpanded{get;}=new();publicMainWindowViewModel(){vargroup=new[]{AIsExpanded,BIsExpanded,CIsExpanded,DIsExpanded};group.AllowOnlyOneTrue();}}}
雑感
RadioButtonのグループ化を真似して添付プロパティにでもした方が楽かもしれない…