2017-01-31 8 views
2

ComboBox私のViewModelのプロパティにバインドされているComboBoxがあります( "VM"について聞いています)。ユーザーがComboBoxを選択すると、VMのバウンドプロパティが正しく更新されます。私のUIコード内で、私はVMのPropertyChangedイベントを購読しています。ComboBoxに関連付けられた値をPropertyChangedイベント内から適切にリセットするにはどうすればよいですか?

ユーザーがComboBox内で選択すると、私のPropertyChangedイベントがUIのバックエンドコードで正しく実行されています。 UIコードがこのプロパティの変更をキャッチすると、特定の選択条件の下でプロセスを停止し、ユーザーに追加情報を要求する必要があります。 UIから、私は彼らにダイアログを送ります。ダイアログをキャンセルすると、ComboBoxコントロールSelectedValueに関連付けられているVMの値がリセットされます。

これは私が観察したものです。ユーザーが操作をキャンセルすると、VMプロパティが新しい値に設定されます。ただし、ComboBoxは、変更された元のエントリのテキスト値をまだ表示しています。 ComboBoxに自分のPropertyChangedイベントから自分自身を更新するにはどうすればよいですか?この場合、バインドされたコレクションのテキストデータを参照しているのは単なるテキストの問題または数値のインデックス変更だと思います。 VM内のデータは正しいですが、ComboBoxの表示値が間違っています。

コンボボックスの詳細VM上の冗長な性質のために申し訳ありません

<ComboBox 
     ItemsSource="{Binding ListOfComboBoxDisplayObjects}" 
     SelectedValue="{Binding MySelectionIsAnEnumeration}" 
     DisplayMemberPath="Text" 
     SelectedValuePath="EnumerationValue" 
     Height="27" /> 

、それは何が起こっているかを説明します。私のListOfComboBoxDisplayObjectsコレクションは、SelectedValuePath内のパスに格納されている一連の列挙値を表します。各値の説明テキストは、UI用に厳密に作成された特別なリストであるListOfComboBoxDisplayObjectsから取得されます。これは、基本的に列挙値を意味のある記述とペアにします。

ListOfComboBoxDisplayObjects定義

(VM内から)[編集]#1 - (VM内から)

private ObservableCollection<BindableEnumerationItem<Values>> _listOfComboBoxDisplayObjects; 
public ObservableCollection<BindableEnumerationItem<Values>> ListOfComboBoxDisplayObjects 
{ 
    get { return _listOfComboBoxDisplayObjects; } 
    private set 
    { 
     if (value != _listOfComboBoxDisplayObjects) 
     { 
      _listOfComboBoxDisplayObjects= value; 
      PropertyChanged(this, new PropertyChangedEventArgs(nameof(ListOfComboBoxDisplayObjects))); 
     } 
    } 
} 

私の例にこの定義を追加しましたMySelectionIsAnEnumeration定義

*編集#1:このコード定義を追加する。

private Values_mySelectionIsAnEnumeration ; 
    public Values MySelectionIsAnEnumeration 
    { 
     get { return _mySelectionIsAnEnumeration; } 
     set 
     { 
      //Double-checked this-- value is different on the second-call to change this value, once the UI cancels the operation. 
      if (value != _mySelectionIsAnEnumeration) 
      { 
       _mySelectionIsAnEnumeration= value; 
       PropertyChanged(this, new PropertyChangedEventArgs(nameof(MySelectionIsAnEnumeration))); 
      } 
     } 
    } 

ListOfComboBoxDisplayObjects

に伴う関連のある値は、これらの値は、VMのctorの中で生成されます。これらはアプリケーション全体で固定されています。

アイテム#1

  • テキスト: "!これはFooのです"
  • 値:値。Fooの

アイテム#2:

  • テキスト: "こんにちは、私はバーです。"
  • 値:Values.Bar

アイテム#3:

  • テキスト: "これはバズで私が使用する前に質問をする必要があります。"
  • 値:Values.Baz

のPropertyChangedイベント - UIバックエンド

private void VM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
     { 
      switch (e.PropertyName) 
      { 
       case "MySelectionIsAnEnumeration": 
        if (VM.MySelectionIsAnEnumeration == Values.Baz) 
        { 
         //Prompt the user and get DialogResult. 
         bool answerGiven = AskAQuestionAndGetAResult(); 
         if(!answerGiven) 
          VM.MySelectionIsAnEnumeration = Values.Foo; 
        } 
        break; 
      } 
     } 

から、上記のコードを実行した後、私が観察してることVM.MySelectionIsAnEnumeration値が実際にあるということですユーザーがAskAQuestionAndGetAResult()の操作をキャンセルしたときに、適切な値のValue.Fooに変更されます。しかし、完了した後にComboBoxはまだと表示されています。「これはBazです。私は使用する前に質問をする必要があります。は明らかにValue.Bazに関連付けられた表示値です。

CombobBoxの基になるVMプロパティと表示テキストの両方を更新して、VM.MySelectionIsAnEnumerationに現在格納されている値を正しく表示するにはどうすればよいですか?

編集以下第2位

は、私がcomboxesやリストボックスのための私の観察可能なコレクションの中に使用したコードefor私BindableEnumerationItemです。これは簡単なケースで私のアプリケーション全体で使用されており、問題は生じていません。これは私の実際の変更されていないコードです。私は何も改名していない。私のコンボボックスは、タイプセーフなプロパティの各Itemプロパティにバインドでき、DisplayTextは記述子テキストです。

+1

ビューでバインディングが更新されない場合、通知またはバインディングエラーがどこかにありません。 'ListOfComboBoxDisplayObjects'、その型と' MySelectionIsAnEnumeration'を表示できますか? – Sinatr

+0

@Sinatr、 'ListOfComboBoxDisplayObjects'内の値は、** ListOfComboBoxDisplayObjects **に関連する関連値の節で提供される値です。この場合、列挙型は 'Values'です。これらは、例を単純化するために作成した任意の値です。バインディングに関しては、すべてのバインディング操作が適切に機能しているように見えます。通常、バインディングに問題がある場合、デバッガは問題をデバッグ出力ウィンドウに出力します。この場合、再割り当て後にメッセージやエラーは表示されません。 – RLH

+0

ユーザーが 'Foo'または' Bar'を選択すると、バインディングが正常に動作していて、ダブルチェックされていることがわかります。 「Baz」でさえ、ユーザがプロンプトに適切に応答すると、適切に動作している。ただし、操作がキャンセルされると、ComboBox内のUI要素はテキストを更新していませんが、VMの基になる値が正しいことは確かです。 – RLH

答えて

0

xamlのviewmodelからのコマンドをセレクタ(この場合はコンボボックス)に配線する拡張を作成します。

public partial class Extensions 
{ 
    public static readonly DependencyProperty SelectionChangedCommandProperty = DependencyProperty.RegisterAttached("SelectionChangedCommand", typeof(ICommand), typeof(Extensions), new UIPropertyMetadata((s, e) => 
    { 
     var element = s as Selector; 

     if (element != null) 
     { 
      element.SelectionChanged -= OnSelectionChanged; 

      if (e.NewValue != null) 
      { 
       element.SelectionChanged += OnSelectionChanged; 
      } 
     } 
    })); 

    public static ICommand GetSelectionChangedCommand(UIElement element) 
    { 
     return (ICommand)element.GetValue(SelectionChangedCommandProperty); 
    } 

    public static void SetSelectionChangedCommand(UIElement element, ICommand value) 
    { 
     element.SetValue(SelectionChangedCommandProperty, value); 
    } 

    private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     var element = sender as Selector; 
     var command = element.GetValue(SelectionChangedCommandProperty) as ICommand; 

     if (command != null && command.CanExecute(element.SelectedItem)) 
     { 
      command.Execute(element.SelectedItem); 
      e.Handled = true; 
     } 
    } 
} 

value changedイベントを処理するコマンドをviewmodelで作成します。

public ICommand EnumerationValueChangedCommand 
{ 
    get 
    { 
     return new Command(
      () => 
       { 
        if (VM.MySelectionIsAnEnumeration == Values.Baz) 
        { 
         //Prompt the user and get DialogResult. 
         bool answerGiven = AskAQuestionAndGetAResult(); 
         if (!answerGiven) 
          VM.MySelectionIsAnEnumeration = Values.Foo; 
        } 
       }); 
    } 
} 

次に、その拡張子を使用してバインドします。 extは拡張機能の名前空間です。

<ComboBox 
    ItemsSource="{Binding ListOfComboBoxDisplayObjects}" 
    SelectedValue="{Binding MySelectionIsAnEnumeration}" 
    DisplayMemberPath="Text" 
    SelectedValuePath="EnumerationValue" 
    ext:Extensions.SelectionChangedCommand="{Binding EnumerationValueChangedCommand}" 
    Height="27" /> 
+0

私はこのアプローチが好きですが、ソースを確認したいと思います。このコードはどこから来たのですか? – RLH

+0

申し訳ありませんが、もう1つ質問です。コマンドは、プロンプトウィンドウを起動する必要があります。それはUIからのプロンプトを起動していますか? – RLH

+0

これはコンボボックスがコマンドの配線性を提供していないことに疲れているセレクタのために書いたもので、MVVMではすべてのロジックがviewmodelになければなりません。コマンドが実行されると、UIスレッドで実行されるので、ユーザを中断したいので、あなたのダイアログはモーダルダイアログにするのが望ましいでしょう。 –

関連する問題