admin管理员组

文章数量:1277901

I'm trying to create a system tray application using Windows Forms using a custom SystemTrayApplicationContext class (inherited from ApplicationContext) that is started during Program.cs:

SystemTrayApplicationContext appContext = new SystemTrayApplicationContext();
Application.ApplicationExit += appContext.HandleExit;
Application.Run(appContext);

The app works fine with only the system tray elements but now I want to add a help screen once a gamepad button is pressed (using Xinputium library, input reading working fine). I'm currently implementing that programmatically with a simple Form instance with a label inside created during SystemTrayApplicationContext's constructor (constructor also sets up ContextMenuStrip and NotifyIcon for the taskbar app).

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();
        }
    }
}

The problem is when showing the help form using Show(), the form appears but not the label. If I use ShowDialog() it will render properly but will freeze the app because it's not modal. I'm unsure what causes the render issue in the first case as I'd like to use Show().

Using Show()

Using ShowDialog()

I currently only have one event for when help key is first pressed and another for when it's released. I'm calling Show for the form when it's pressed and Hide when it's released. The Form variable itself is just a private field created inside SystemTrayApplicationContext.

Tried using ShowDialog. Setting Visible in the inner label, setting properties like AutoSize, ActiveControl and background color in the form but nothing had an effect.

I'm trying to create a system tray application using Windows Forms using a custom SystemTrayApplicationContext class (inherited from ApplicationContext) that is started during Program.cs:

SystemTrayApplicationContext appContext = new SystemTrayApplicationContext();
Application.ApplicationExit += appContext.HandleExit;
Application.Run(appContext);

The app works fine with only the system tray elements but now I want to add a help screen once a gamepad button is pressed (using Xinputium library, input reading working fine). I'm currently implementing that programmatically with a simple Form instance with a label inside created during SystemTrayApplicationContext's constructor (constructor also sets up ContextMenuStrip and NotifyIcon for the taskbar app).

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();
        }
    }
}

The problem is when showing the help form using Show(), the form appears but not the label. If I use ShowDialog() it will render properly but will freeze the app because it's not modal. I'm unsure what causes the render issue in the first case as I'd like to use Show().

Using Show()

Using ShowDialog()

I currently only have one event for when help key is first pressed and another for when it's released. I'm calling Show for the form when it's pressed and Hide when it's released. The Form variable itself is just a private field created inside SystemTrayApplicationContext.

Tried using ShowDialog. Setting Visible in the inner label, setting properties like AutoSize, ActiveControl and background color in the form but nothing had an effect.

Share Improve this question asked Feb 24 at 16:56 Anderson UrbanoAnderson Urbano 11 silver badge2 bronze badges 2
  • I guess you miss some initialization stuff. Instead of using Form helpForm and doing code-behind, add a new form to your project, use designer (it will take care of most of stuff for you with generated code) and show it as you do now. – Sinatr Commented Feb 24 at 17:02
  • You're using a third-party library for the input events. Have you checked whether these events are raised in a different Thread? In that case, you have to marshal the .Show() method to the current SynchronizationContext. .ShowDialog() creates a nested message loop that can pump the messages required by the UI – Jimi Commented Feb 24 at 17:57
Add a comment  | 

1 Answer 1

Reset to default 0

I was able to make it work by creating a custom help form class that inherits from Form and overriding the OnLoad method to make it invisible.

Then, passing it to the base ApplicationContext constructor to populate MainForm. Unsure why this works though.

本文标签: cWindows Forms help Form not displaying correctly using Show() methodStack Overflow