Windows Forms帮助窗体调用Show()无法正常显示标签的问题
问题描述
我用Windows Forms开发系统托盘应用,通过自定义的SystemTrayApplicationContext(继承自ApplicationContext)启动,代码如下:
SystemTrayApplicationContext appContext = new SystemTrayApplicationContext(); Application.ApplicationExit += appContext.HandleExit; Application.Run(appContext);
仅保留系统托盘元素时运行正常,现在希望按下游戏手柄按键(使用Xinputium库,输入读取功能正常)时显示帮助界面。我在SystemTrayApplicationContext的构造函数中编程创建了包含Label的Form实例,同时设置了任务栏的ContextMenuStrip和NotifyIcon:
using System; using System.Drawing; using System.Windows.Forms; using XInputium; using XInputium.XInput; public class SystemTrayApplicationContext : ApplicationContext { private readonly XGamepad xinputDevice = new XGamepad(); private Form helpForm; private NotifyIcon trayIcon; private ContextMenuStrip contextMenuStrip; private ToolStripMenuItem exitLabel; public SystemTrayApplicationContext() { // Setup help screen Label label = new Label(); label.Text = "test"; label.Size = new Size(300, 300); label.Anchor = AnchorStyles.Left; label.TextAlign = ContentAlignment.TopCenter; this.helpForm = new Form(); this.helpForm.Size = label.Size; this.helpForm.ShowInTaskbar = false; this.helpForm.ShowIcon = false; this.helpForm.ControlBox = false; this.helpForm.FormBorderStyle = FormBorderStyle.None; this.helpForm.StartPosition = FormStartPosition.CenterScreen; this.helpForm.Controls.Add(label); // SetupContextMenu this.exitLabel = new ToolStripMenuItem("Exit"); this.exitLabel.Anchor = AnchorStyles.Right; this.exitLabel.Click += this.HandleExit; this.contextMenuStrip = new ContextMenuStrip(); this.contextMenuStrip.ShowImageMargin = false; this.contextMenuStrip.Items.Add(exitLabel); this.trayIcon = new NotifyIcon() { Icon = Properties.Resources.AppIcon, Visible = true, Text = "My System Tray App", ContextMenuStrip = this.contextMenuStrip, }; // Setup Xinput events this.xinputDevice.ButtonPressed += this.HandleXinputButtonPressed; this.xinputDevice.ButtonReleased += this.HandleXinputButtonReleased; } public void HandleExit(object sender, EventArgs e) { trayIcon.Visible = false; Application.Exit(); } private void HandleXinputButtonPressed(object sender, DigitalButtonEventArgs<XInputButton> e) { if (e.Button.Button == XButtons.A) { this.helpForm.Show(); //this.helpForm.ShowDialog(); } } private void HandleXinputButtonReleased(object? sender, DigitalButtonEventArgs<XInputButton> e) { if (e.Button.Button == XButtons.A) { this.helpForm.Hide(); } } }
问题:使用Show()显示帮助窗体时,窗体出现但Label不显示;使用ShowDialog()时渲染正常,但会阻塞应用。希望使用Show(),但不清楚渲染异常的原因,尝试过设置Label的Visible属性、窗体的AutoSize等均无效。
解决方案
问题根源是XInputium的事件回调在非UI线程触发,而Windows Forms控件的所有操作必须在创建它的UI线程执行。直接在非UI线程调用helpForm.Show()会导致控件渲染异常,所以Label无法显示;ShowDialog()内部会自动切换到UI线程上下文,因此能正常渲染,但会阻塞线程。
解决方法是在事件回调中通过Invoke切换到UI线程再操作窗体:
修改按键按下和释放的处理方法:
private void HandleXinputButtonPressed(object sender, DigitalButtonEventArgs<XInputButton> e) { if (e.Button.Button == XButtons.A) { this.helpForm.Invoke(() => this.helpForm.Show()); } } private void HandleXinputButtonReleased(object? sender, DigitalButtonEventArgs<XInputButton> e) { if (e.Button.Button == XButtons.A) { this.helpForm.Invoke(() => this.helpForm.Hide()); } }
这样就能保证窗体和控件的操作都在UI线程执行,Show()时Label也能正常显示,同时不会阻塞应用。
内容的提问来源于stack exchange,提问作者Anderson Urbano
相关产品推荐
相关产品推荐

