在ComboBox上撤消SourceUpdated绑定操作

时间:2012-03-13 14:18:54

标签: wpf binding combobox undo

我的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
    }
}

我很难将ComboBox恢复为原始值(在上面代码的“TODO”评论中)。

我尝试的第一个也是最明显的事情就是简单地改回DataContext的SelectedValueMember的值,假设绑定会更新ComboBox:

MyDataContext.SelectedValueMember = original_value;

当我这样做时,在调试器中我可以看到它确实更新了SelectedValueMember值,但是ComboBox没有更改回来 - 它保留了新值。

有什么想法吗?


以下

AngelWPF的答案有效,可能是最新,最清晰的方式。

然而,我确实找到了一个非显而易见的解决方案:

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将操作放在第二个UI线程上,它就可以了!我可能是错的,但我的预感是,为了避免绑定更新循环,直接在源/目标更新处理程序中的操作不会受到绑定的反应。

2 个答案:

答案 0 :(得分:3)

使用UpdateSourceTrigger =“Explicit”添加到AngelWPF的答案:

稍微更简洁的方法是使用BindingExpression.UpdateSource()和BindingExpression.UpdateTarget()方法。 UpdateSource()将值从UI控件移动到ViewModel,UpdateTarget()以相反的方向移动数据。使用这些方法可以使您不必执行以下代码:

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

与AngelWPF的体验相反,在我的情况下,我确实必须在用户取消时将ComboBox恢复为原始值,即使我将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();
    }
}

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

答案 1 :(得分:2)

对于显式条件更新绑定中的源,使用 updatesource触发器作为Explicit 并处理组合框的选择更改事件以执行与基于源的同步在消息框结果。

    <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绑定到一组项目(称为MyData),其中NameID为属性。 ComboBox的选定值绑定到另一个名为MyID的属性。现在,请注意UpdateSourceTrigger=Explicit绑定中的SelectedValue

我在选择更改时同步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;
            }
        }
    }

这种方式没有必要恢复。源明确更新,您可以完全控制它。