2012-03-13 8 views
0

マイComboBoxにSourceUpdated結合操作の取り消し:は、コンボボックス

<ComboBox 
    SourceUpdated="MyComboBox_SourceUpdated" 
    ItemsSource="{Binding ...}" 
    SelectedValue="{Binding Path=SelectedValueMember, NotifyOnSourceUpdated=True}" 
    SelectedValuePath="..." 
    DisplayMemberPath="..." 
/> 

そして、私のSourceUpdatedハンドラ:

private void MyComboBox_SourceUpdated(object sender, DataTransferEventArgs args) { 
    if (/* user answers no to an 'are you sure?' prompt */) { 
     // TODO: revert ComboBox back to original value 
    } 
} 

私はに(元の値に戻ってコンボボックスを元に戻すことは困難抱えています」上記の私のコードの "TODO"コメント)。

私が試した最初の、そして最も明白なことは、単純にDataContextのSelectedValueMemberの値をバックに変更した、バインディングと仮定するとコンボボックスの更新になります。私はこれを行うと

MyDataContext.SelectedValueMember = original_value; 

を、デバッガでIそれが実際にSelectedValueMember値を更新していることがわかりますが、ComboBoxは変更されません。新しい値に保持されます。

アイデア?


AngelWPFの作品以下の答えとは、おそらくneatestと明確な方法です。

私はしかし、非自明な解決策を見つけた:

private void MyComboBox_SourceUpdated(object sender, DataTransferEventArgs args) { 
    if (/* user answers no to an 'are you sure?' prompt */) { 
     Dispatcher.BeginInvoke(new Action(() => { 
      MyDataContext.SelectedValueMember = original_value; 
     })); 
    } 
} 

をするだけBeginInvokeによって第2のUIスレッド上で操作を置くことによって、それが動作します!私は間違っている可能性がありますが、私は、更新ループのバインディングを避けるために、ソース/ターゲット更新ハンドラのアクションはバインディングによって反応しないということです。

+0

SelectedValueMemberで 'PropertyChanged'を発生させますか?あるいはそれは 'DependencyProperty'です。 – Silvermind

+0

はい、PropertyChangedイベントが発生します。テストを行い、MyDataContext.SelectedValueMemberの値を変更する唯一の目的で単純なボタンを接続すると、ソースとターゲットのバインディングがうまく動作し、ComboBoxが更新されます。 – Ross

+0

似たような質問と回答があります:http://stackoverflow.com/questions/2585183/wpf-combobox-selecteditem-change-to-previous-value/2709931#2709931私はエンジェルの答えはおそらく最高だと思うが、バインディングで明示的なモードにしたくない場合は、BeginInvokeを使うこともできます。 – NathanAW

答えて

2

、結合ソースの明示条件更新については、メッセージボックスの結果に基づいてソースとの同期を実行するために、コンボボックスの選択変更イベントを明示としてupdatesourceトリガを使用してハンドル。

<StackPanel DataContext="{StaticResource MyObject}"> 
     <ComboBox ItemsSource="{Binding MyData}" 
      DisplayMemberPath="Name" 
      SelectedValuePath="ID" 
      SelectedValue="{Binding Path=MyID, 
            Mode=TwoWay, 
            UpdateSourceTrigger=Explicit}" 
      SelectionChanged="ComboBox_SelectionChanged"> 
     </ComboBox> 
     <TextBlock Text="{Binding Path=MyID}"/> 
    </StackPanel> 

のでComboBoxはプロパティとしてNameIDを持つ(MyDataと呼ばれる)アイテムのコレクションにバインドされています。 ComboBoxの選択された値はMyIDという別のプロパティにバインドされています。今度はSelectedValueのバインディングにUpdateSourceTrigger=Explicitと言っています。

する必要がないとき、コンボボックスの選択値の選択が変更されると、ユーザーは以下のようにメッセージボックスにYesを選択した場合にのみ...

private void ComboBox_SelectionChanged 
     (object sender, SelectionChangedEventArgs e) 
    { 
     var bndExp 
      = BindingOperations.GetBindingExpression(
       (ComboBox) sender, Selector.SelectedValueProperty); 
     if (bndExp != null && bndExp.ParentBinding != null) 
     { 
      if (MessageBox.Show(
        "Are you sure?", 
        "Sure?", 
        MessageBoxButton.YesNo) == MessageBoxResult.Yes) 
      { 
       ((MyObject) bndExp.DataItem).MyID 
        = (int)((ComboBox) sender).SelectedValue; 
      } 
     } 
    } 

Thsiの方法私はMyIDを同期方法元に戻す。ソースは明示的に更新され、すべてのコントロールがあります。

A少しクリーンな方法でこれを行うにはBindingExpression.UpdateSource()とBindingExpression.UpdateTarget()メソッドを使用することです:=「明示的な」UpdateSourceTriggerを使用してAngelWPFの答えにに追加

3

。 UpdateSource()はUIコントロールからViewModelに値を移動し、UpdateTarget()は反対方向にデータを移動します。これらのメソッドを使用すると、このコード行を行うには手間が省けます:

((MyObject) bndExp.DataItem).MyID = (int)((ComboBox) sender).SelectedValue; 

AngelWPFの経験に反して、私の状況で私は、ユーザーがさえIかかわらず、キャンセルされた場合が元の値にコンボボックスを元に戻す必要がありましたBinding.UpdateSourceTriggerをExplicitに設定しました。これはTelerik RadComboBoxのためか、以前のコメントが間違っていた可能性があります。私はこの時点では言いません。しかし、次のいずれかの方法で、コードを読みやすくなります。

private void OfficeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    var comboBox = (RadComboBox) sender; 
    var binding = comboBox.GetBindingExpression(RadComboBox.SelectedValueProperty); 

    if(MessageBox.Show("Are you sure?", "Are you sure?", MessageBoxButton.YesNo) == MessageBoxResult.Yes) 
    { 
     binding.UpdateSource(); 
    } 
    else 
    { 
     binding.UpdateTarget(); 
    } 
} 

必要に応じて独自のヌルチェックを追加します。