通常,绑定是使用Ca中的可视化表示形式连接C#中的数据的一种非常方便的方法。数据更改时,视觉表示也会自动更新。但是,如果您有成千上万个绑定,并且大多数都位于当前不在屏幕上的页面上,则使所有隐藏的视觉表示保持最新状态似乎很愚蠢且昂贵。但是,如您所见,如果您运行下面的示例,则默认情况下绑定就是这样做的!即使我从屏幕上删除了CountingBlock
,每次BreakpointConverter
更新时,它仍然继续呼叫我的Counter
。
对我来说,在卸载时停止更新是更有意义的,然后作为LoadedEvent的一部分,重新激活我的所有绑定,同时检查源已更新为什么。 有没有办法做到这一点?
谢谢
Xaml:
<Window x:Class="DeactivateBindings.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="800">
<UniformGrid>
<ContentControl Name="Container"/>
<Button Content="Show or Hide" Click="ShowOrHide_Click"/>
</UniformGrid>
</Window>
转换器:
class BreakpointConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value; // does nothing, but you can set a breakpoint here to see if the binding is active.
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
背后的代码
public partial class MainWindow : Window
{
bool _isCounterVisible;
Label CountingBlock = new Label { FontSize = 25 };
public MainWindow()
{
InitializeComponent();
ContingBlock.SetBinding(Label.ContentProperty, new Binding
{
Source = this,
Path = new PropertyPath(nameof(Counter)),
// this Converter is the key component that tells us the binding is still active, because we can breakpoint it.
Converter = new BreakpointConverter(),
});
StartCounting();
}
private async void StartCounting()
{
while(true)
{
Counter++;
await Task.Delay(500);
}
}
private void ShowOrHide_Click(object sender, RoutedEventArgs e)
{
_isCounterVisible = !_isCounterVisible;
Countainer.Content = _isCounterVisible ? CountingBlock : null;
}
public int Counter
{
get { return (int)GetValue(CounterProperty); }
set {SetValue(CounterProperty, value); }
}
public static readonly DependencyProperty CounterProperty =
DependencyProperty.Register(nameof(Counter), typeof(int), typeof(MainWindow), new PropertyMetadata(0));
}
答案 0 :(得分:0)
一种选择是在离开页面时将所有绑定更改为显式,然后稍后再将其更改。 Explicit
表示绑定仅在您告知绑定时更新,而不在任何后备属性更改时更新。重新加载UIElement时,可以再次重新激活所有绑定。
// this will allow us to keep track of the real UpdateSourceTriggers for our bindings
private Dictionary<BindingExpression, UpdateSourceTrigger> _deactivatedBindings = new Dictionary<BindingExpression, UpdateSourceTrigger>();
public static void OnUnloaded(object sender, RoutedEventArgs e)
{
foreach(BindingExpreesion expression in GetBindingPaths(sender as DependencyObject))
expression.DeactivateBindings();
}
public static void OnLoaded(object sender, RoutedEventArgs e)
{
foreach(BindingExpreesion expression in GetBindingPaths(sender as DependencyObject))
expression.ReactivateBindings();
}
public static asynce Task DeactivateBindings(this BindingExpression oldExpression)
{
// you can't modify bindings once they've been used, so we'll copy the old one, modify it, and use that one instead
Binding duplicateBinding = oldExpression.ParentBinding.Clone();
// this means that the binding won't update when the property changes, just when we tell it to.
duplicateBinding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
// here we save the 'real' value - the one we use when the element is loaded.
_deactivatedBindings[duplicateBinding] = oldExpression.ParentBinding.UpdateSourceTrigger;
BindingOperations.SetBinding(oldExpression.Target, oldExpression.TargetProperty, duplicateBinding);
}
public static async Task ReactivateBindings(this BindingExpression oldExpression)
{
if(_deactivatedBindings.TryGetValue(oldExpression.ParentBinding, out UpdateSourceTrigger realTrigger))
{
_deactivatedBindings.Remove(oldExpression.ParentBinding);
Binding duplicateBinding = oldExpression.ParentBinding.Clone();
duplicateBinding.UpdateSourceTrigger = realTrigger;
// This has the added advantage of refreshing the value so it's up to date. :)
BindingOperations.SetBinding(oldExpression.Target, oldExpression.TargetProperty, duplicateBinding);
}
}
GetBindingPaths() Method-仅保存BindingExpressions而不是路径。