WPF中如何确保在用户控件完全加载后执行指定方法?
你现在遇到的情况我太懂了——用Loaded事件的时候总以为控件已经完全渲染好了,结果发现代码跑在控件真正显示之前,确实挺坑的。先理下你的场景:
我有两个XAML/WPF用户控件,第一个控件的按钮点击事件里会把当前Content切换成第二个控件:
private void AutoSetupPageOneConfirmButton_Click(object sender, RoutedEventArgs e) { this.Content = new AutoSetupPageTwo(); }第二个页面能打开,但我需要在它完全加载后再运行一些方法,现在方法总是先执行,页面才完全加载。试了
Loaded和Initialized事件都没用,感觉这俩事件更像是“正在加载”的触发点,不是“加载完成”。
给你几个亲测有效的解决办法:
用Dispatcher延迟执行,指定低优先级
控件的Loaded事件触发时,逻辑树已经构建完成,但可能还没完成最终的UI渲染。这时候把要执行的方法放到Dispatcher.BeginInvoke里,设置优先级为DispatcherPriority.Render(或者更低的DispatcherPriority.Loaded),就能保证在控件真正显示出来后再执行代码。在
AutoSetupPageTwo的后台代码里这么写:public AutoSetupPageTwo() { InitializeComponent(); this.Loaded += AutoSetupPageTwo_Loaded; } private void AutoSetupPageTwo_Loaded(object sender, RoutedEventArgs e) { // 把目标方法丢到Dispatcher队列,等渲染完成后执行 Dispatcher.BeginInvoke(new Action(() => { // 这里替换成你要执行的方法 YourTargetMethod(); }), DispatcherPriority.Render); }因为
DispatcherPriority.Render的任务会在UI渲染全部完成后才被处理,完全能满足你的需求。在父控件中结合Content变化事件+Dispatcher
要是你不想在AutoSetupPageTwo里写逻辑,想在第一个控件里统一处理,也可以这么做:private void AutoSetupPageOneConfirmButton_Click(object sender, RoutedEventArgs e) { var newPage = new AutoSetupPageTwo(); this.Content = newPage; // 让Dispatcher在所有当前UI操作完成后再执行方法 Dispatcher.BeginInvoke(new Action(() => { newPage.YourTargetMethod(); }), DispatcherPriority.ContextIdle); }ContextIdle的优先级会等当前所有UI相关的任务都处理完才会触发,也能确保控件完全加载好。临时应急:检查IsLoaded属性(不推荐)
要是赶时间想快速测试,也可以循环检查控件的IsLoaded属性,直到它为true再执行方法,但这个方式可能会有线程阻塞的风险,尽量少用:private void AutoSetupPageOneConfirmButton_Click(object sender, RoutedEventArgs e) { var newPage = new AutoSetupPageTwo(); this.Content = newPage; // 循环等待直到控件加载完成,同时让出线程避免卡死 while (!newPage.IsLoaded) { System.Windows.Forms.Application.DoEvents(); } newPage.YourTargetMethod(); }
备注:内容来源于stack exchange,提问作者George

