如何防止WPF C#中RDC重连时页面与UC触发加载卸载方法?
解决WPF远程桌面重连时控件重复加载/重建问题
一、修复Loaded事件重复添加控件的问题
你的代码中每次用户控件实例化都会绑定Loaded事件,而RDC重连导致控件重建时,Loaded会再次触发,重复创建TextBox。可以通过两种方式解决:
事件触发后解绑
在事件处理方法内移除自身绑定,确保只执行一次:public uc() { Loaded += somemethod; } private void somemethod(object sender, RoutedEventArgs e) { // 解绑事件,避免重复触发 Loaded -= somemethod; TextBox tb = new TextBox(); this.AddChild(tb); }检查控件是否已存在
先遍历子控件,避免重复创建:private void somemethod(object sender, RoutedEventArgs e) { if (!this.Children.OfType<TextBox>().Any()) { TextBox tb = new TextBox(); this.AddChild(tb); } }
二、阻止RDC重连时的控件树重建
WPF在远程桌面重连时会响应DisplaySettingsChanged或SessionSwitch事件,默认重建可视化树。可以通过以下方式干预:
处理会话切换事件
在应用启动时注册SessionSwitch事件,捕获远程重连动作,手动维护控件状态:SystemEvents.SessionSwitch += (sender, e) => { if (e.Reason == SessionSwitchReason.RemoteConnect) { // 暂停可视化树重建逻辑,或保存当前控件状态 var source = PresentationSource.FromVisual(Application.Current.MainWindow); source?.CompositionTarget?.Rendering -= YourRenderingHandler; // 对于数据模板控件,可提前缓存模板实例,避免重复创建 } };优化数据模板复用
针对数据模板内控件重建问题,使用VirtualizingStackPanel并开启缓存,或自定义模板选择器缓存已创建的模板实例:<ItemsControl ItemsSource="{Binding DataList}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.CacheLength="5" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <!-- 你的模板内容 --> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
三、调试构造函数触发的原因
堆栈显示外部代码时,可通过以下方式追踪调用源:
开启外部代码显示
在Visual Studio的调用堆栈窗口右键,勾选「显示外部代码」,即可查看完整的调用路径,找到触发控件实例化的源头。记录调用栈日志
在构造函数中添加调用栈日志,输出到调试窗口:public uc() { var stackTrace = new System.Diagnostics.StackTrace(true); System.Diagnostics.Debug.WriteLine($"uc构造函数调用栈:\n{stackTrace}"); Loaded += somemethod; }查看调试输出窗口的日志,定位具体的调用方。
四、持久化控件状态
对于需要保留的控件状态,在Unloaded事件中保存,Loaded时恢复,避免重建导致数据丢失:
private string _textBoxContent; public uc() { Loaded += somemethod; Unloaded += (s, e) => { var tb = this.Children.OfType<TextBox>().FirstOrDefault(); if (tb != null) _textBoxContent = tb.Text; }; } private void somemethod(object sender, RoutedEventArgs e) { Loaded -= somemethod; var tb = this.Children.OfType<TextBox>().FirstOrDefault() ?? new TextBox(); tb.Text = _textBoxContent; if (tb.Parent == null) this.AddChild(tb); }
内容的提问来源于stack exchange,提问作者dheuv
相关产品推荐
相关产品推荐

