2012-03-13 64 views
0

ComboBox一个SourceUpdated绑定操作:撤消上一个ComboBox

<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; 

当我做到这一点,在调试器我可以看到它确实正在更新SelectedValueMember值,但ComboBox不会变回 - 它保留在新值上。

任何想法?


AngelWPF的回答下面的作品,并可能是最整洁和清晰的方式。

我也不过,找到一个非显而易见的解决方案:只需通过将操作的第二UI线程通过BeginInvoke手段

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; 
     })); 
    } 
} 

,它的作品!我可能是错的,但我的直觉是为了避免绑定更新循环,直接在源/目标更新处理程序中的操作不会被绑定反应。

+0

您是否在SelectedValueMember上提升'PropertyChanged'?或者它是一个'DependencyProperty'。 – Silvermind 2012-03-13 14:33:32

+0

Yep一个PropertyChanged事件引发。如果我测试并连接一个简单的按钮,其唯一目的是更改MyDataContext.SelectedValueMember的值,那么源目标绑定工作正常,ComboBox更新。 – Ross 2012-03-13 14:41:09

+0

这里有一个类似的问题和答案:http://stackoverflow.com/questions/2585183/wpf-combobox-selecteditem-change-to-previous-value/2709931#2709931。我认为Angel的答案可能是最好的,但如果你不想在绑定上使用显式模式,那么使用BeginInvoke也可以。 – NathanAW 2012-03-13 15:43:44

回答

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的属性。现在请注意UpdateSourceTrigger=ExplicitSelectedValue的绑定。

我同步的MyID的方式,当所述选择的变化,与仅当用户选择如下面一个消息框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方式没有必要对还原。源明确更新,并且您可以完全控制它。

3

使用UpdateSourceTrigger =“明确的”添加到AngelWPF的回答是:

稍微清洁的方式做到这一点是使用了BindingExpression.UpdateSource()和BindingExpression.UpdateTarget()方法。 UpdateSource()将UI控件的值移动到ViewModel,并且UpdateTarget()以相反的方向移动数据。使用这些方法不必做这行的代码为您节省:

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

出乎AngelWPF的经验,在我的情况我有恢复的组合框回到原来的值时,用户即使我取消将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(); 
    } 
} 

根据需要添加您自己的空检查。