暂停控件的数据绑定

我有一系列控件,它们数据绑定到每秒钟左右变化的值。 有时,我需要“暂停”控件,这样他们就不会更新数据绑定(在任何一个方向上)。 然后,我需要“取消暂停”控件,以便他们可以使用其值更新数据源,并正常接收来自源的未来更新。 我该如何做到这一点?

样本绑定:

 

您不一定要暂停绑定。 另一种可能更简单的方法是在视图模型中暂停更改通知。 例如:

 private HashSet _ChangedProperties = new HashSet(); private void OnPropertyChanged(string propertyName) { if (_Suspended) { _ChangedProperties.Add(propertyName); } else { PropertyChangedEventHandler h = PropertyChanged; if (h != null) { h(this, new PropertyChangedEventArgs(propertyName)); } } } private bool _Suspended; public bool Suspended { get { return _Suspended; } set { if (_Suspended == value) { return; } _Suspended = value; if (!_Suspended) { foreach (string propertyName in _ChangedProperties) { OnPropertyChanged(propertyName); } _ChangedProperties.Clear(); } } } 

这将(如果它已经过调试和测试,我还没有完成)当Suspended设置为true时停止引发PropertyChanged事件,并且当Suspended再次设置为false时,它将为暂停时更改的每个属性引发事件。

这不会阻止更改绑定控件以更新视图模型。 我向你提交,如果你让用户在屏幕上编辑属性,同时你在背景中更改它们,那么你需要仔细查看一些内容,而且它不具有约束力。

要处理源,请将UpdateSourceTrigger设置为Explicit

  

然后在代码后面引用一个服务,它可以处理由你的条件定义的实际更新。

 BindingExpression be = myTextBox.GetBindingExpression(TextBox.TextProperty); be.UpdateSource(); 

这将允许您指定数据从目标返回源的点。

可以通过调用相同的引用服务来解决目标,该服务具有何时在ViewModel中调用INotifyPropertyChanged.PropertyChanged事件的知识。

  class Data : INotifyPropertyChanged { Manager _manager; public Data(Manager manager) { _manager = manager; } public event PropertyChangedEventHandler PropertyChanged; String _info = "Top Secret"; public String Information { get { return _info; } set { _info = value; if (!_manager.Paused) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs("Information")); } } } } 

首先,您需要创建显式绑定:

 Binding binding = new Binding("Content"); binding.Source = source; binding.UpdateSourceTrigger = UpdateSourceTrigger.LostFocus; binding.Mode = BindingMode.TwoWay; txtContent.SetBinding(TextBox.TextProperty, binding); 

然后当你需要暂停twoway绑定时,你需要销毁旧绑定并使用显式触发器创建新的单向绑定(在这种情况下,当某些属性被更改时,绑定源将不会更新):

 BindingOperations.ClearBinding(txtContent, TextBlock.TextProperty); Binding binding = new Binding("Content"); binding.Source = source; binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit; binding.Mode = BindingMode.OneWay; txtContent.SetBinding(TextBox.TextProperty, binding); 

当你需要恢复twoway绑定时,你可以显式更新源(如果你需要),而不是破坏单向绑定并创建双向绑定。

 BindingExpression be = txtContent.GetBindingExpression(TextBox.TextProperty); be.UpdateSource(); BindingOperations.ClearBinding(txtContent, TextBlock.TextProperty); Binding binding = new Binding("Content"); binding.Source = source; binding.UpdateSourceTrigger = UpdateSourceTrigger.LostFocus; binding.Mode = BindingMode.TwoWay; txtContent.SetBinding(TextBox.TextProperty, binding); 

如果您在控制器类中保留对视图的引用,则可以在要暂停数据包的情况下从视图模型中触发事件,该数据包使控制器清除视图的DataContext。 当您准备好再次开始发送接收数据时,请将Views DataContext重置为View Model。

如果要挂起的控件具有您拥有的DataContext(ViewModel),则只需将其保存并将DataContext置空。

如果控件具有inheritance的DataContext,则将该控件的DataContext设置为null将阻止inheritance。 然后,为了恢复绑定更新,您使用ClearValue方法清除DataContext DependencyProperty,以便inheritance再次启动。

在清除DataContext之前,您可以使用VisualBrush来截取您要挂起的控件的屏幕截图,这样用户就不会看到控件变为空白。

我的解决方案最终结果如下,以防止在用户尝试更改文本时更新文本。

XAML:

   

代码背后:

  private void TextBox_OnGotFocus([CanBeNull] object sender, [CanBeNull] RoutedEventArgs e) { TextBox tb = sender as TextBox; if (tb == null) return; BindingExpression expression = tb.GetBindingExpression(TextBox.TextProperty); if (expression == null) return; // disable updates from source BindingOperations.ClearBinding(tb, TextBlock.TextProperty); tb.SetBinding(TextBox.TextProperty, new Binding(expression.ParentBinding.Path.Path) { Mode = BindingMode.OneWayToSource, UpdateSourceTrigger = UpdateSourceTrigger.Explicit , FallbackValue = tb.Text}); } private void TextBox_OnLostFocus([CanBeNull] object sender, [CanBeNull] RoutedEventArgs e) { TextBox tb = sender as TextBox; if (tb == null) return; BindingExpression expression = tb.GetBindingExpression(TextBox.TextProperty); if (expression == null) return; // send current value to source expression.UpdateSource(); // enable updates from source BindingOperations.ClearBinding(tb, TextBlock.TextProperty); tb.SetBinding(TextBox.TextProperty, new Binding(expression.ParentBinding.Path.Path) { Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.LostFocus }); } 

请注意,我将当前文本指定为OneWayToSource绑定的回退值以具有起始值(否则文本字段在聚焦后将为空)