Wpf 撤消组合框上的SourceUpdated绑定操作

Wpf 撤消组合框上的SourceUpdated绑定操作,wpf,binding,combobox,undo,Wpf,Binding,Combobox,Undo,我的组合框: <ComboBox SourceUpdated="MyComboBox_SourceUpdated" ItemsSource="{Binding ...}" SelectedValue="{Binding Path=SelectedValueMember, NotifyOnSourceUpdated=True}" SelectedValuePath="..." DisplayMemberPath="..." /> 我很难将组合框

我的
组合框

<ComboBox
    SourceUpdated="MyComboBox_SourceUpdated"
    ItemsSource="{Binding ...}"
    SelectedValue="{Binding Path=SelectedValueMember, NotifyOnSourceUpdated=True}"
    SelectedValuePath="..."
    DisplayMemberPath="..."
/>
我很难将组合框恢复到其原始值(在上面代码的“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线程上,它就可以工作了!我可能错了,但我的直觉是,为了避免绑定更新循环,源/目标更新处理程序中的直接操作不会被绑定响应。

对于绑定中源的显式
条件更新,使用updatesource触发器作为显式并处理combobox的selection changed事件,根据消息框结果执行与源的同步

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

这样就不需要恢复了。源显式更新,您可以对其进行所有控制。

对于绑定中源的显式条件更新,使用updatesource触发器作为显式,并处理combobox的selection changed事件,根据消息框结果执行与源的同步

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

这样就不需要恢复了。源代码显式更新,您可以对其进行控制。

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

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

((MyObject) bndExp.DataItem).MyID = (int)((ComboBox) sender).SelectedValue;
与AngelWPF的经验相反,在我的情况下,当用户取消时,即使我将Binding.UpdateSourceTrigger设置为Explicit,我也必须将ComboBox恢复为原始值。也许这是因为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();
    }
}

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

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

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

((MyObject) bndExp.DataItem).MyID = (int)((ComboBox) sender).SelectedValue;
与AngelWPF的经验相反,在我的情况下,当用户取消时,即使我将Binding.UpdateSourceTrigger设置为Explicit,我也必须将ComboBox恢复为原始值。也许这是因为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();
    }
}

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

您是否在SelectedValueMember上引发
PropertyChanged
?或者它是一个
dependencProperty
。是的,引发了PropertyChanged事件。如果我做了一个测试并连接了一个简单的按钮,其唯一目的是更改MyDataContext.SelectedValueMember的值,那么源到目标绑定工作正常,组合框会更新。下面是一个类似的问题和答案:。我认为Angel的答案可能是最好的,但是如果您不想在绑定上使用显式模式,那么使用BeginInvoke也可以。您是否在SelectedValueMember上提出
PropertyChanged
?或者它是一个
dependencProperty
。是的,引发了PropertyChanged事件。如果我做了一个测试并连接了一个简单的按钮,其唯一目的是更改MyDataContext.SelectedValueMember的值,那么源到目标绑定工作正常,组合框会更新。下面是一个类似的问题和答案:。我认为Angel的答案可能是最好的,但是如果您不想在绑定上使用显式模式,那么使用BeginInvoke也可以。