我有一系列控件可以数据绑定到每隔一秒左右更改一次的值。有时,我需要“暂停”控件,这样他们就不会更新数据绑定(在任何一个方向上)。然后,我需要“取消暂停”控件,以便他们可以使用其值更新数据源,并正常接收来自源的未来更新。我该如何做到这一点?
示例绑定:
<TextBox Text="{Binding UpdateSourceTrigger=LostFocus, Mode=TwoWay, Path=myData}">
答案 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
时以及true
为Suspended
时停止提升false
个事件再次设置为{{1}},它会为暂停时更改的每个属性引发事件。
这不会阻止更改绑定控件以更新视图模型。我向你提交,如果你让用户在屏幕上编辑属性,同时你在后台更改它们,那么你需要仔细查看一些内容,而且它不具有约束力。
答案 1 :(得分:3)
要处理来源设置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"));
}
}
}
}
答案 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绑定的后备值以具有起始值(否则,一旦聚焦,文本字段将为空)