You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何防止WPF C#中RDC重连时页面与UC触发加载卸载方法?

解决WPF远程桌面重连时控件重复加载/重建问题

一、修复Loaded事件重复添加控件的问题

你的代码中每次用户控件实例化都会绑定Loaded事件,而RDC重连导致控件重建时,Loaded会再次触发,重复创建TextBox。可以通过两种方式解决:

  1. 事件触发后解绑
    在事件处理方法内移除自身绑定,确保只执行一次:

    public uc()
    {
        Loaded += somemethod;
    }
    
    private void somemethod(object sender, RoutedEventArgs e)
    {
        // 解绑事件,避免重复触发
        Loaded -= somemethod;
        TextBox tb = new TextBox();
        this.AddChild(tb);
    }
    
  2. 检查控件是否已存在
    先遍历子控件,避免重复创建:

    private void somemethod(object sender, RoutedEventArgs e)
    {
        if (!this.Children.OfType<TextBox>().Any())
        {
            TextBox tb = new TextBox();
            this.AddChild(tb);
        }
    }
    

二、阻止RDC重连时的控件树重建

WPF在远程桌面重连时会响应DisplaySettingsChanged或SessionSwitch事件,默认重建可视化树。可以通过以下方式干预:

  1. 处理会话切换事件
    在应用启动时注册SessionSwitch事件,捕获远程重连动作,手动维护控件状态:

    SystemEvents.SessionSwitch += (sender, e) =>
    {
        if (e.Reason == SessionSwitchReason.RemoteConnect)
        {
            // 暂停可视化树重建逻辑,或保存当前控件状态
            var source = PresentationSource.FromVisual(Application.Current.MainWindow);
            source?.CompositionTarget?.Rendering -= YourRenderingHandler;
            
            // 对于数据模板控件,可提前缓存模板实例,避免重复创建
        }
    };
    
  2. 优化数据模板复用
    针对数据模板内控件重建问题,使用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>
    

三、调试构造函数触发的原因

堆栈显示外部代码时,可通过以下方式追踪调用源:

  1. 开启外部代码显示
    在Visual Studio的调用堆栈窗口右键,勾选「显示外部代码」,即可查看完整的调用路径,找到触发控件实例化的源头。

  2. 记录调用栈日志
    在构造函数中添加调用栈日志,输出到调试窗口:

    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 14:32:12