暂停控件的数据绑定

时间:2011-02-10 20:41:42

标签: c# .net wpf user-interface data-binding

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

示例绑定:

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

6 个答案:

答案 0 :(得分:12)

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

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

这将(如果经过调试和测试,我还没有完成)在PropertyChanged设置为Suspended时以及trueSuspended时停止提升false个事件再次设置为{{1}},它会为暂停时更改的每个属性引发事件。

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

答案 1 :(得分:3)

要处理来源设置UpdateSourceTriggerExplicit

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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

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

答案 5 :(得分:0)

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

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