プロフィール

ハンドル
くろい えのぐ
twitter
@enogu

たぶんプログラマ
主にPHP版汝は人狼なりや?のメンテナンスなどをやっているとかいないとか。

使っている言語はC#とPHPとときどきC。Javascript(かDart)をマスターしたい。

最近更新された記事

FormItでメールフォームを作成する
2013-08-20
Quip ー MODXページにコメント欄をつける
2012-08-20
MODX Revolutionのアクセス制御について
2012-07-18
せめて日本人に何となく伝わってほしいポインタの話
2012-06-13
MODXでブログを作ってみた その1:getResources
2012-04-04

タグ

  • PHP (1)
  • Silverlight (1)
  • xPDO (1)
  • 残念なお知らせ (2)
  • OpenIndiana (2)
  • PIC (2)
  • MODX (8)
  • SelectorのSelectedItemを保持する方法

    作成日: 2011-12-06 / タグ: Silverlight

    この記事は Silverlight Advent Calendar 2011 8日目の記事です。

    masa-kさんが2日目の記事でComboBoxのSelectedItemをどうにかしたいと仰っていたので、ナイス!ナイス振り!!今回は私が過去に踏んだSelector系のコントロールで発生する問題の傾向と対策についていくつかご紹介します。

    前提

    経験上この問題はSelectorのデータコンテキストのバインディングが解除された時点で起こります。masa-kさんの記事ではListBoxのテンプレートにComboBoxを入れられていましたが、私の場合は普通のGridの中に組み込んだComboBoxでGridのデータコンテキストを切り替えたときに発生しました。

    症状

    Selectorのデータコンテキストのバインディングが解除されるとSelectedIndexがDataContextより先にリセットされます。これによってSelectedIndexとかSelectedItemとTwoWayバインディングしたプロパティには予期しない値が入ることになります。masa-kさんのケースではコンテナがアンロードされた時点で発症しているのではないかと思われます。

    対策

    力業ですが、私はビューモデル側で予期しないSelectedIndexの更新を受け付けを拒否する方法を採っています。ビューモデルにAllowUpdateSourceプロパティを作成して、都合の悪いときはこのプロパティをfalseに設定します。あとは更新されると困るプロパティのセッターでAllowUpdateSourceプロパティを参照して更新を受け入れるかどうか切り替えることになります。

    public class ListItemViewModel : INotifyPropertyChanged {
    //
    //(中略)
    //
        private bool allowUpdateSource = true;
        public bool AllowUpdateSource {
            get { return this.allowUpdateSource; }
            set {
                if (this.allowUpdateSource != value) {
                    this.allowUpdateSource = value;
                    this.RaisePropertyChanged("AllowUpdateSource");
                }
            }
        }
    }
    

    ListBoxの仮想化でアンロードされるケースについては経験がなかったのでいくつか試してみたのですが、結論としてはイベントトリガーでChangePropertyActionを実行してAllowUpdateSourceプロパティを変更する形で実装できました。このとき、Loaded/Unloadedイベントで対応するよりGotFocus/LostFocusイベントをトリガーにした方が期待通りに動いてくれるようです。

    <DataTemplate x:Key="ComboTemplate">
      <Grid>
        <ComboBox d:LayoutOverrides="Height"
         ItemsSource="{Binding Items}"
         SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
         MinWidth="120">
          <i:Interaction.Triggers>
            <i:EventTrigger EventName="GotFocus">
              <ei:ChangePropertyAction
               TargetObject="{Binding Mode=OneWay}"
               PropertyName="AllowUpdateSource" Value="True"/>
            </i:EventTrigger>
            <i:EventTrigger EventName="LostFocus">
              <ei:ChangePropertyAction
               TargetObject="{Binding Mode=OneWay}"
               PropertyName="AllowUpdateSource" Value="False"/>
            </i:EventTrigger>
          </i:Interaction.Triggers>
        </ComboBox>
      </Grid>
    </DataTemplate>
    

    まだ検証が甘いので、この方法で上手くカバーできない手順があったらご連絡下さい。

    サンプル

    ソースコードはこちら