C# 当控件未加载时,是否有方法停用绑定?
一般来说,绑定是连接C#中的数据和Xaml中的可视化表示的一种非常方便的方法。当数据更改时,视觉表示也会自动更新。但是,如果您有数千个绑定,并且大多数绑定都位于当前不在屏幕上的页面上,那么将所有隐藏的视觉表示保持最新似乎既愚蠢又昂贵。但正如您所看到的,如果您运行下面的示例,这正是绑定在默认情况下所做的!即使我从屏幕上删除C# 当控件未加载时,是否有方法停用绑定?,c#,xaml,data-binding,C#,Xaml,Data Binding,一般来说,绑定是连接C#中的数据和Xaml中的可视化表示的一种非常方便的方法。当数据更改时,视觉表示也会自动更新。但是,如果您有数千个绑定,并且大多数绑定都位于当前不在屏幕上的页面上,那么将所有隐藏的视觉表示保持最新似乎既愚蠢又昂贵。但正如您所看到的,如果您运行下面的示例,这正是绑定在默认情况下所做的!即使我从屏幕上删除CountingBlock,每次计数器更新时,它都会继续调用我的断点转换器 对我来说,在卸载时停止更新更有意义,然后作为LoadedEvent的一部分,重新激活我的所有绑定,同时
CountingBlock
,每次计数器更新时,它都会继续调用我的断点转换器
对我来说,在卸载时停止更新更有意义,然后作为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>
背后的代码:
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));
}
一种选择是在离开页面时将所有绑定更改为显式,然后稍后再将其更改回显式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);
}
}
//这将允许我们跟踪绑定的实际更新资源记录器
私有字典_deactivatedBindings=新字典();
未加载的公共静态无效(对象发送方,路由目标)
{
foreach(GetBindingPath中的BindingExpression表达式(发送方作为DependencyObject))
表达式。停用索引();
}
已加载公共静态无效(对象发送器,路由目标e)
{
foreach(GetBindingPath中的BindingExpression表达式(发送方作为DependencyObject))
表达式。重新激活索引();
}
公共静态异步任务停用索引(此BindingExpression-oldExpression)
{
//一旦绑定被使用,您就不能修改它们,因此我们将复制旧绑定,修改它,然后使用该绑定
Binding duplicateBinding=oldExpression.ParentBinding.Clone();
//这意味着绑定不会在属性更改时更新,而只是在我们告诉它时更新。
duplicateBinding.UpdateSourceTrigger=UpdateSourceTrigger.Explicit;
//在这里,我们保存“真实”值—加载元素时使用的值。
_deactivatedBindings[duplicateBinding]=oldExpression.ParentBinding.UpdateSourceTrigger;
BindingOperations.SetBinding(oldExpression.Target、oldExpression.TargetProperty、duplicateBinding);
}
公共静态异步任务重新激活Bindings(此BindingExpression-oldExpression)
{
if(_deactivatedBindings.TryGetValue(oldExpression.ParentBinding,out UpdateSourceTrigger realTrigger))
{
_deactivatedBindings.Remove(oldExpression.ParentBinding);
Binding duplicateBinding=oldExpression.ParentBinding.Clone();
duplicateBinding.UpdateSourceTrigger=realTrigger;
//这还具有刷新值的附加优势,因此它是最新的。:)
BindingOperations.SetBinding(oldExpression.Target、oldExpression.TargetProperty、duplicateBinding);
}
}
-只需保存BindingExpressions而不是路径
// 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);
}
}