2009-03-19 74 views
37

WPF MVVMコンボボックスのSelectedItemまたはSelectedValueのは、調査の少し後に更新

を働いていません。問題は、アイテムソースの読み込みが完了する前にSelectedValue/SelectedItemが発生していることです。私がブレークポイントに座って数秒待っても、期待どおりに動作します。どのように私はこの1つを回避しようとしているのか分からない。

エンド更新

私はコンボボックスでMVVMを使用してWPFで使用してアプリケーションを持っています。以下はViewModelの例です。私が抱えている問題は、私たちのページを離れ、コンボボックスが選択されている現在の値を選択していない状態に戻るときです。

ビューモデル

public class MyViewModel 
{ 
    private MyObject _selectedObject; 
    private Collection<Object2> _objects; 
    private IModel _model; 

    public MyViewModel(IModel model) 
    { 
     _model = model; 
     _objects = _model.GetObjects(); 
    } 

    public Collection<MyObject> Objects 
    { 
     get 
     { 
       return _objects; 
     } 
     private set 
     { 
       _objects = value; 
     } 
    } 

    public MyObject SelectedObject 
    { 
      get 
      { 
       return _selectedObject; 
      } 
      set 
      { 
       _selectedObject = value; 
      } 
     } 
} 

この例のためにMyObjectには、2つのプロパティ(テキストやID)を持って言うことができます。 ComboBoxのXAMLは次のようになります。

XAML

<ComboBox Name="MyComboBox" Height="23" Width="auto" 
    SelectedItem="{Binding Path=SelectedObject,Mode=TwoWay}" 
    ItemsSource="{Binding Objects}" 
    DisplayMemberPath="Text" 
    SelectedValuePath="Id"> 

私は戻っページに来て、オブジェクトがコンボボックスに値を選択しないだろう再組み立てされたとき、私はこれを設定する方法に関係なく。オブジェクトはプロパティのgetを介して正しいオブジェクトを返しています。

これは、ComboBoxとMVVMパターンの仕組みに問題があるかどうかはわかりません。私たちがやっているテキストボックスのバインディングは正しく動作します。

答えて

24

INotifyPropertyChangedをviewmodelに実装してから、SelectedItemが設定されたときにPropertyChangedイベントを発生させましたか?

これだけでは問題が解決しない場合は、ページに戻るときに手作業でPropertyChangedイベントを発生させることができます。これは、WPFに再描画され、正しい選択項目。

+0

UserControl_Loadedイベントにディスパッチャを追加することで問題を解決しました。私はPropertyChangeを上げていますが、コンボボックスは空白のままです。 – cjibo

+0

もし私がブレークポイントを入れて、ちょっと待ってもそれはうまくいく。私は、コンボボックスのバインディングが完了する前に、私の選択した項目が設定されていると思っています。 Urgh。 – cjibo

+1

私はPorpertyChangedイベントをナビゲーション上でページに戻すのを忘れました。 – cjibo

9

私は同様の問題を抱えており、私が実装していることを確認して解決しましたIEquatableが適切に実行されています。バインディングが発生すると、オブジェクトが一致するかどうかを確認しようとしているので、等価チェックが適切に実装されていることを確認してください。

+0

私もこれを試しました。 MyObjectでIEquatableを実装し、.idフィールドにマッチさせてtrueを返します。それも効果がありません。プロパティにバインドされたテキストボックスを追加すると、ページに戻ると正しい情報が表示されます。 – cjibo

3

私は以前にもこの動作に気付きました。私はSelectedIndexプロパティが同じバグを引き起こさないことに気付きました。 ViewModelを再構成して、選択した項目のインデックスを公開し、それにバインドすることができれば、行かなくてはなりません。

0

これは、DataContextをページに適用する方法です。 WPFでは、ページに移動するたびにすべてが再初期化され、コンストラクタが呼び出され、メソッドがロードされます。そのため、ビュー内にDataContextを設定している場合、ユーザが選択したSelectedItemを吹き飛ばすことは間違いありません。あなたのページのKeepAliveプロパティの使用を避けるために。

<Page KeepAlive="True" ...> 
    ... 
</Page> 

これにより、既に訪問したページに戻るときにLoadedイベントだけが発生します。したがって、Loadではなく、Initialize(外部またはコンストラクタ内)でDataContextを設定する必要があります。

ただし、これはページのそのインスタンスでのみ機能します。そのページの新しいインスタンスに移動すると、コンストラクターが再度呼び出されます。

+0

MVVMパターンを使用しているため、XAMLページのコードがありません。 Loadイベントはありません。すべてがデータバインディングを介して行われています。そのため、テンプレートは、View Modelのプロパティに基づいてDataTemplateSelectorによって選択されています。 – cjibo

2

私は同じ問題がありました。事はです。選択された項目は、コレクションからどのオブジェクトを使用すべきかわかりません。したがって、コレクションからアイテムを使用するには、選択したアイテムに言わなければなりません。

public MyObject SelectedObject 
{ 
     get 
     { 
      Objects.find(x => x.id == _selectedObject.id) 
      return _selectedObject; 
     } 
     set 
     { 
      _selectedObject = value; 
     } 
} 

これが役立ちます。

0

ComboBox.SelectionBoxItem.ToString()

0

IsSyncronizedWithCurrent = Falseの場合、それを動作させるでしょう。

20

SelectedItemプロパティの前にItemsSourceプロパティを配置する必要があります。私は数日前にこの問題について言及したブログに出くわしました。

+0

はい、これは私のために解決しました.. – Rogier

+0

これは本当にありがとうございました。私はこのことがすべて終わったとき、自分のXAMLやView Modelで何が間違っていたのか理解しようとしていました。 – ShadowLiberal

+0

ボッシュ、素晴らしい答え! – dibs487

0

使用Loadedイベント:

private void cmb_Loaded(object sender, RoutedEventArgs e) { 
    if (cmb.Items.Count > 0) cmb.SelectedIndex = 0;   
} 

それは私のために動作します。

1

私はしばらくこの問題で戦っていました。私の場合は、Item Sourceとして複合型(List)を使用していて、KeyTypeを選択値として使用していました。 loadイベントでは、KeyTypeがnullに設定されていました。これですべてが壊れました。キーが変更されたときに、サブ要素のどれも更新されませんでした。 KeyTypeの提案された値がnullでないことを確認するためのチェックを追加すると、すべてが期待どおりに機能することが判明しました。現在のページを離れるときは、ComboBoxItemsSourceプロパティに関連付けられたCollectionViewがパージされる

#region Property: SelectedKey 
    // s.Append(string.Format("SelectedKey : {0} " + Environment.NewLine, SelectedKey.ToString())); 

    private KeyType _SelectedKey = new KeyType(); 
    public KeyType SelectedKey 
    { 
     get { return _SelectedKey; } 
     set 
     { 
      if(value != null) 
       if (!_SelectedKey.Equals(value)) 
       { 
        _SelectedKey = value; 
        OnPropertyChanged("SelectedKey"); 
       } 
     } 
    } 
    #endregion SelectedKey 
4

。既定でComboBoxIsSyncronizedWithCurrentプロパティがtrueであるため、SelectedItemSelectedValueのプロパティがリセットされます。
これはバインディングの内部データ型の問題のようです。上で提案したように、viewmodelのintプロパティにバインドする代わりにSelectedValueを使用すると機能します。 MyObjectでEquals演算子をオーバーライドすると、2つのMyObjectを比較するときに実際のIdプロパティが比較されるようになります。

もう一つのヒント:あなたのviewmodelsを再構築し、SelectedValueを使用し、SelectedValuePath=IdIdintある場合のみ、ときにそれを使用しない場合。文字列キーを使用する場合は、SelectedValueの代わりにのTextプロパティにバインドします。

+1

私は非常に似た問題を抱えています。問題の理由は、ItemsSourceがRelativeSourceにバインドされ、SelectedItem/SelectedValueがDataContextに直接バインドされているためです。私はそれを解決することができましたが、問題の理由は明らかではありません。ここでは、同じ問題を抱えている人のために説明します:http://stackoverflow.com/questions/33739513/wpf-mvvm-combobox-selectedvalue-is-cleared-when-navigating-away –

1

SelectedValuePathSelectedValueのタイプはまったく同じでなければなりません。例えばSelectedValuePathのタイプはInt16で、SelectedValueに結合するプロパティのタイプがある場合

intそれは動作しません。

私はそれを見つけるのに何時間も費やしています。だからこそ、私はずっと質問を聞いてからここに答えています。同じ問題を抱えている私のような別の貧しい人が見えるかもしれません。

2

私はこの問題について非常に単純な答えを持っています。まず、次のコードをView IsSynchronizedWithCurrentItem = "True"に追加します。

次の場合、ViewModelの新しいオブジェクトをそのプロパティに割り当てるときは、SelectedObjectプロパティはプライベートメンバーではなくそのプロパティに保存する必要があります。

のviewmodel Propteryは、この問題を修正する必要があり、この

public Role SelectedObject 
    { 
     get { return object; } 
     set 
     { 
      if (value != null) 
      { 
       if (!object.Equals(value)) 
       { 
        object = value; 
        OnPropertyChanged(() => SelectedObject); 
       } 
      } 
     } 
    } 

のようになります。

1

色のリストを表示するComboBoxでこの問題が発生しました(リスト<ブラシ>)。色を選択
が可能であったが、それは選択を閉じたときに表示波平(プロパティが変更されたが!)

修正は、コンボボックス(ブラシ)で選択されたタイプのための等号(オブジェクトobj)メソッドを上書きしました。これは、ブラシが封印されているのでシンプルではありませんでした。代わりに、問題を修正し、通常のブラシクラスの私の新しいEqualityBrushクラスのリストを使用して

public class EqualityBrush 
{ 
    public SolidColorBrush Brush { get; set; } 

    public override bool Equals(object o) 
    { 
     if (o is EqualityBrush) 
     { 
      SolidColorBrush b = ((EqualityBrush)o).Brush; 
      return b.Color.R == this.Brush.Color.R && b.Color.G == this.Brush.Color.G && b.Color.B == this.Brush.Color.B; 
     } 
     else 
      return false; 
    } 
} 

: は、だから私は、クラスEqualityBrushブラシを含むとequalsを実装を書きました!

マイコンボボックスXAMLは次のようになります。

<ComboBox ItemsSource="{Binding BuerkertBrushes}" SelectedItem="{Binding Brush, Mode=TwoWay}" Width="40"> 
    <ComboBox.Resources> 
     <DataTemplate DataType="{x:Type tree:EqualityBrush}"> 
      <Rectangle Width="20" Height="12" Fill="{Binding Brush}"/> 
     </DataTemplate> 
    </ComboBox.Resources> 
</ComboBox> 

ViewModelにでの私の "ブラシ" -Propertyは今タイプEqualityBrushでなければならないことを忘れないでください!

23

設定IsSynchronizedWithCurrentItem="True"が私のために働いた!

+0

はい、ありがとうございます。 –

+0

Wimに感謝します。このもので40分間苦労していた。 – sander

+0

これで苦労しました。これは私にとって完璧に機能しました。ありがとう:) –

9

この場合、オブジェクトのハッシュIDが異なるため、選択されたアイテムバインドは機能しません。

一つの可能​​な解決策は、次のとおり選択されたアイテムIDに基づい

、itemsourceコレクションにオブジェクトを回収し、それを用いて、選択した項目のプロパティを設定します。

例:のSelectedItemにバインドさプロパティがある

public ObservableCollection<Profile> Profiles 
{ 
    get { return this.profiles; } 
    private set { profiles = value; RaisePropertyChanged("Profiles"); } 
} 

<ctrls:ComboBoxControlBase SelectedItem="{Binding Path=SelectedProfile, Mode=TwoWay}" ItemsSource="{Binding Path=Profiles, Mode=OneWay}" IsEditable="False" DisplayMemberPath="Name" /> 

プロパティItemSourceにバインドさがされて

public Profile SelectedProfile 
{ 
    get { return selectedProfile; } 
    set 
    { 
     if (this.SelectedUser != null) 
     { 
      this.SelectedUser.Profile = value; 
      RaisePropertyChanged("SelectedProfile"); 
     } 
    } 
} 

回復コードは次のとおりです。

[Command("SelectionChanged")] 
    public void SelectionChanged(User selectedUser) 
    { 
     if (selectedUser != null) 
     { 
      if (selectedUser is User) 
      { 
       if (selectedUser.Profile != null) 
       { 
        this.SelectedUser = selectedUser; 
        this.selectedProfile = this.Profiles.Where(p => p.Id == this.SelectedUser.Profile.Id).FirstOrDefault(); 
        MessageBroker.Instance.NotifyColleagues("ShowItemDetails"); 
       } 
      } 
     }    
    } 

私はそれがあなたを助けてくれることを願っています。 私は多くの時間をかけて答えを探しましたが、私は見つけることができませんでした。

+0

この素晴らしい!ありがとう –

0

私は、私たちの実際の実装はINotifyPropertyChangedのを実装ViewBaseクラスから継承

Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => 
{ 
    combobox.SelectedIndex = 0; 
})); 
関連する問題