atelier:mitsuba

i love UI/UX, Blend, XAML, Behavior, P5, oF, Web, Tangible Bits and Physical computing. なにかあればお気軽にご連絡ください。atelier@c-mitsuba.com

XAML系プラットフォームでItemsControlで生成したExpanderを一度に開閉したいとき。

こういうシチュで、右のToggleButton (x:Name = "toggle")押したらー
f:id:c-mitsuba:20150909155934p:plain
こうなってほしくって、
f:id:c-mitsuba:20150909155938p:plain
こういう中途半端に開いてるやつもー
f:id:c-mitsuba:20150909160226p:plain
がばっっと開いてー
f:id:c-mitsuba:20150909160245p:plain
こういう中途半端に開いてるやつもー
f:id:c-mitsuba:20150909160233p:plain
ガッっっと閉じたいとき
f:id:c-mitsuba:20150909160242p:plain

とりあえずExpanderを作りたいので、サンプルデータセットを作って、
てきとーにBindingして、ItemTemplateを書きます。
こんなかんじ。
f:id:c-mitsuba:20150909160820p:plain
f:id:c-mitsuba:20150909160816p:plain

で、ExpanderのIsExpandedプロパティをtoggleのIsCheckedにBinding

<Expander x:Name="expander" Header="Expander" IsExpanded="{Binding IsChecked, ElementName=toggle, Mode=OneWay}"/>

するとー。
toggleをぽちぽちする分にはいいかんじに、動きます。
f:id:c-mitsuba:20150909155934p:plain
f:id:c-mitsuba:20150909155938p:plain

が、一度でもExpanderをクリックして開閉したものは、toggleをクリックしても反応しなくなります。
ちなみに、縦に並べているToggleButtonは想定した動きをします。

今回はWPFで作成したので、SnoopでクリックしたExpanderとクリックしてないExpanderを見比べてみます。
触ったExpander
f:id:c-mitsuba:20150909161802p:plain
触ってないExpander
f:id:c-mitsuba:20150909161804p:plain
Expanderの内部の処理で、Bindingがふっとばされているのがわかります。
なるほど、OneWayだとふっとぶ。。

次にTwoWayを試してみます。

<Expander x:Name="expander" Header="Expander" IsExpanded="{Binding IsChecked, ElementName=toggle, Mode=TwoWay}"/>

予想どおり、どっか開いたら全部開くし、どっか閉じたら全部閉じるし、だめなかんじ。
でも、Bindingはふっとばない。

ここで本題、設定はTwoWayだけど、OneWayみたいにすればいいじゃない。
ということでコンバータを書きます。こんなかんじ。

public class NonBindingConverter :IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

ぱっと見、なにもしないコンバータですが、こんなふうにつかいます。

<Expander x:Name="expander" Header="Expander" IsExpanded="{Binding IsChecked, Converter={StaticResource NonBindingConverter}, ElementName=toggle, Mode=TwoWay}">

すると、toggleのIsCheckが変化したら、Expanderにそのまま反映しますが、

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    return value;
}

ExpanderのIsExpandedはtoggleのIsCheckedに反映しません。

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
    return Binding.DoNothing;
}

なので、振る舞いはOneWayだけど、設定はTwoWayになります。
TwoWayだからBinding式は飛ばないし、挙動はOneWayなのでExpanderを個別に触ってもtoggleで開いたり閉じたりできます。
あれげコンバータに見えるけど、めでたしめでたし。