繁体   English   中英

暂停控件的数据绑定

[英]Suspend Databinding of Controls

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

样本绑定:

<TextBox Text="{Binding UpdateSourceTrigger=LostFocus, Mode=TwoWay, Path=myData}">

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

private HashSet<string> _ChangedProperties = new HashSet<string>();

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

<TextBox Name="myTextBox" Text="{Binding UpdateSourceTrigger=Explicit, Mode=TwoWay, Path=myData}">

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

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(ViewModel),则只需将其保存并将DataContext置空。

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

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

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

XAML:

<TextBox Grid.Row="0" Grid.Column="1" TextAlignment="Right" VerticalAlignment="Center" Text="{Binding Path=MinimumValueInDisplayUnit, StringFormat=0.########}" MinWidth="100" Margin="4" GotFocus="TextBox_OnGotFocus" LostFocus="TextBox_OnLostFocus"/>
<TextBox Grid.Row="0" Grid.Column="2" TextAlignment="Right" VerticalAlignment="Center" Text="{Binding Path=MaximumValueInDisplayUnit, StringFormat=0.########}" MinWidth="100" Margin="4" GotFocus="TextBox_OnGotFocus" LostFocus="TextBox_OnLostFocus"/>

代码背后:

    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绑定的回退值以具有起始值(否则文本字段在聚焦后将为空)

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM