I am trying to learn GTK# (obviously in C#). I am using Ubuntu and I compile with mono. I want to create a MenuBar and add some Menu, and MenuItem to it.
When I compile, all is OK but my menu isn't displaying.
public MainWindow() : base("LayText")
{
SetDefaultSize(800, 600);
SetPosition(WindowPosition.Center);
DeleteEvent += delegate { Application.Quit(); };
this.InitializeComponent();
ShowAll();
}
private void InitializeComponent()
{
this.m_new = new MenuItem("Nouveau fichier");
this.m_open = new MenuItem("Ouvrir fichier");
this.m_exit = new MenuItem("Quitter");
this.file = new Menu();
this.file.Append(this.m_new);
this.file.Append(this.m_open);
this.file.Append(this.m_exit);
this.menu_file = new MenuItem("Fichier");
this.menu_file.Submenu = this.file;
this.menu_bar = new MenuBar();
this.menu_bar.Append(this.menu_file);
this.vbox_princ = new VBox(false, 2);
this.vbox_princ.PackStart(this.menu_bar, false, false, 0);
this.Add(this.vbox_princ);
}
When I compile this code I am getting the window but without the menu I've set.
Screenshot of the window
Thanks for helping me.
Layce17
The following code (just a modification/completion or yours) works perfectly. I see you are using Ubuntu. Though I don't use it, I think it shows the menu bar in the top status bar. Have you checked that out?
using Gtk;
namespace Kk
{
class MainWindow: Gtk.Window {
public MainWindow() : base("LayText")
{
SetDefaultSize(800, 600);
SetPosition(WindowPosition.Center);
DeleteEvent += delegate { Application.Quit(); };
this.InitializeComponent();
ShowAll();
}
private void InitializeComponent()
{
var m_new = new MenuItem("Nouveau fichier");
var m_open = new MenuItem("Ouvrir fichier");
var m_exit = new MenuItem("Quitter");
var file = new Menu();
file.Append(m_new);
file.Append(m_open);
file.Append(m_exit);
var menu_file = new MenuItem("Fichier");
menu_file.Submenu = file;
var menu_bar = new MenuBar();
menu_bar.Append(menu_file);
var vbox_princ = new VBox(false, 2);
vbox_princ.PackStart(menu_bar, false, false, 0);
this.Add(vbox_princ);
}
public static void Main()
{
Application.Init();
new MainWindow();
Application.Run();
}
}
}
Hope this helps.
Related
In a .NET Framework 4.8 winform app without main form I have this code:
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Daemon());
}
public class Daemon : ApplicationContext
{
private readonly NotifyIcon trayIcon;
public Daemon()
{
trayIcon = new NotifyIcon()
{
Icon = "icon.ico",
ContextMenu = new ContextMenu(new MenuItem[]
{
new MenuItem("OPEN", new EventHandler(Open)),
new MenuItem("SETTINGS", new EventHandler(Settings)),
new MenuItem("EXIT", new EventHandler(Exit))
}),
Visible = true
};
}
}
In a .NET 5 (or 6) win form app, the NotifyIcon object doesn't have a ContextMenu property, but a ContextMenuStrip that I don't understand how to use.
How can I create a simple menu on a try icon for an application that doesn't have a main form?
Same as the accepted answer but slightly more concise, for better or worse:
public Daemon()
{
trayIcon = new NotifyIcon()
{
Icon = new Icon("icon.ico"),
ContextMenuStrip = new ContextMenuStrip()
{
Items =
{
new ToolStripMenuItem("OPEN", null, new EventHandler(Open), "OPEN"),
new ToolStripMenuItem("SETTINGS", null, new EventHandler(Settings), "SETTINGS"),
new ToolStripMenuItem("EXIT", null, new EventHandler(Exit), "EXIT")
}
},
Visible = true
};
}
If that Items = {...} syntax seems strange, see here.
Also, here is a table showing the Windows Forms classes that were removed in .NET Core 3 and their corresponding replacements.
It was simpler than expected.
public Daemon()
{
trayIcon = new NotifyIcon()
{
Icon = new Icon("icon.ico"),
ContextMenuStrip = new ContextMenuStrip(),
Visible = true
};
trayIcon.ContextMenuStrip.Items.AddRange(new ToolStripItem[]
{
new ToolStripMenuItem("OPEN", null, new EventHandler(Open), "OPEN"),
new ToolStripMenuItem("SETTINGS", null, new EventHandler(Settings), "SETTINGS"),
new ToolStripMenuItem("EXIT", null, new EventHandler(Exit), "EXIT")
});
}
I know this is such a noob question, but I am trying to learn and test. One of my self-imposed challenges is creating a NotifyIcon in the systray (easy) and then clicking a button and making the icon change on interval from green to red based on the current icon value. However, when I try to read the value of NotifyIcon.Icon, it is just (Icon). I expect it to be an ico file I have in Properties.Resources (i.e. Properties.Resources.icon.ico).
using System;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Threading;
namespace TEST_NotifyIconChange
{
public partial class MainWindow : Window
{
private NotifyIcon notifyIcon = new NotifyIcon();
private ContextMenuStrip ContextMenuStrip_System_Tray = new ContextMenuStrip();
private DispatcherTimer iconAnimationTimer = new DispatcherTimer();
public MainWindow()
{
InitializeComponent();
iconAnimationTimer.Interval = TimeSpan.FromSeconds(1);
iconAnimationTimer.Tick += IconAnimationTimer_Tick;
iconAnimationTimer.IsEnabled = false;
ResetAll();
}
private void ResetAll()
{
notifyIcon.ContextMenuStrip = ContextMenuStrip_System_Tray;
notifyIcon.Icon = Properties.Resources.icon_green;
notifyIcon.Text = "I am just a standard icon";
notifyIcon.Visible = true;
}
private void ChangeColorButton_Click(object sender, RoutedEventArgs e)
{
if (iconAnimationTimer.IsEnabled == false)
{
iconAnimationTimer.IsEnabled = true;
iconAnimationTimer.Start();
}
else
{
iconAnimationTimer.Stop();
iconAnimationTimer.IsEnabled = false;
}
}
private void IconAnimationTimer_Tick(object sender, EventArgs e)
{
if (notifyIcon.Icon == Properties.Resources.icon_green)
{
Console.WriteLine("Changing to red");
notifyIcon.Icon = Properties.Resources.icon_red;
}
else
{
Console.WriteLine("Changing to green");
notifyIcon.Icon = Properties.Resources.icon_green;
}
}
}
}
notifyIcon.Icon == Properties.Resources.icon_green will never return true, because every time that you call it, it returns a new instance of the Icon.
You don't need to track the assigned icon; instead, you need to track of the status and based on the status, assign an icon. To track the status you can use Tag property of NotifyIcon or a member field of the Form. But do not look at the Icon property as a status indicator.
Just in case you are interested to compare two Icon objects to see whether they are same icon, you can use the following method:
bool AreIconsEqual(Icon ico1, Icon ico2)
{
byte[] bytes1, bytes2;
using (var fs = new MemoryStream())
{
ico1.Save(fs);
bytes1 = fs.ToArray();
}
using (var fs = new MemoryStream())
{
ico2.Save(fs);
bytes2 = fs.ToArray();
}
return bytes1.SequenceEqual(bytes2);
}
I have problem with getting of FolderBrowserDialog in white. I think that it should be assigned as a modal window but it isn't.
FolderBrowserDialog in DialogService.cs:
public FolderBrowserResult ShowFolderbrowserDialog(string storageFolder)
{
var dialog = new FolderBrowserDialog
{
Description = storageFolder
};
var result = new FolderBrowserResult
{
Result = dialog.ShowDialog() != DialogResult.OK,
Path = dialog.SelectedPath
};
return result;
}
Method called after click on browse button:
private void OnBrowseForTargetFolder(object sender, RoutedEventArgs e)
{
var result = dialogService.ShowFolderbrowserDialog(Properties.Resources.StorageFolder);
if (result.Result) return;
Project.PathToStorage = result.Path;
completePath = string.Format("{0}\\{1}", result.Path, Guid.NewGuid());
Directory.CreateDirectory(completePath);
}
Test:
public class LoggerTests
{
private Application application;
private MainWindowPage mainWindowPage;
[TestInitialize]
public void TestInitialize()
{
application = Application.Launch(#"PML.exe");
StartBlankApplication();
}
[TestMethod]
public void StartExistingProject()
{
mainWindowPage.StartExistingProjectButton.Click();
var modalWindows = new List<Window>();
Retry.For(() =>
{
modalWindows = mainWindowPage.applicationWindow.ModalWindows();
}, TimeSpan.FromSeconds(5));
var mod = modalWindows;
}
private MainWindowPage StartBlankApplication()
{
var appWindow = application.GetWindow("PML");
mainWindowPage = new MainWindowPage(appWindow);
return mainWindowPage;
}
private NewProjectConfigurationPage ConfigureBlankProject()
{
Window secondAppWindow = null;
Retry.For(() =>
{
secondAppWindow = application.GetWindow("PML");
}, TimeSpan.FromSeconds(5));
var newProjectConfiguration = new NewProjectConfigurationPage(secondAppWindow);
newProjectConfiguration.VesselName.Text = "Test";
newProjectConfiguration.BrowseButton.Click();
return newProjectConfiguration;
}
}
In StartExistingProject method is problem that variable mod is empty. And no FolderBrowserDialog is opened. But when I run app normally everything runs OK.
Solved - There must be setted owner to modal dialog. So
var wrapper = new WindowWrapper(this);
dialog.ShowDialog(wrapper)
solved my problem.
I seem to have a problem with two lines of code in my program.
A ThreadStateException occurs at the lines if (o.ShowDialog() == DialogResult.OK) and if(s.ShowDialog() == DialogResult.OK)
The program is supposed to interpret a made up language, but that part of code has not been made yet. Please help, I have no idea what to do!
public class meow : Form
{
TextBox meowbox = new TextBox();
private string titile;
public meow()
{
titile="Tiger goes Meow";
Size = new Size(500, 600);
Text =titile ;
meowbox.Size = new Size(450, 520);
meowbox.Multiline = true;
meowbox.ScrollBars = ScrollBars.Horizontal;
meowbox.WordWrap = true;
meowbox.Location = new Point(25, 10);
//file
MenuItem feow = new MenuItem("File Meow");
MenuItem oeow = new MenuItem("open Meow");
MenuItem seow = new MenuItem("Save Meow");
feow.MenuItems.Add(oeow);
feow.MenuItems.Add(seow);
//run
MenuItem leow = new MenuItem("Meow");
MenuItem ceow = new MenuItem("Check Meow");
MenuItem reow = new MenuItem("Run Meow");
leow.MenuItems.Add(ceow);
leow.MenuItems.Add(reow);
//menu
MainMenu beow = new MainMenu();
Menu = beow;
beow.MenuItems.Add(feow);
beow.MenuItems.Add(leow);
//put it all meow
Controls.Add(meowbox);
//handlers
oeow.Click += new EventHandler(oeow_Click);
seow.Click += new EventHandler(seow_Click);
/*ceow.Click += new EventHandler(ceow_Click);
reow.Click += new EventHandler(reow_Click);*/
}
protected void oeow_Click( object sender, EventArgs e){
Text="Oeow";
OpenFileDialog o = new OpenFileDialog();
if (o.ShowDialog() == DialogResult.OK)
{
Stream file = o.OpenFile();
StreamReader reader = new StreamReader(file);
char[] data = new char[file.Length];
reader.ReadBlock(data, 0, (int)file.Length);
meowbox.Text = new String(data);
reader.Close();
}
Text = titile;
}
protected void seow_Click(object sender, EventArgs e)
{
Text="seow";
SaveFileDialog s = new SaveFileDialog();
if(s.ShowDialog() == DialogResult.OK)
{
StreamWriter writer = new StreamWriter(s.OpenFile());
writer.Write(meowbox.Text);
writer.Close();
}
Text=titile;
}
public static void Main()
{
Application.Run(new meow());
}
}
If the code you posted is your real program, then the problem is that you aren't setting the thread's apartment state correctly. The main Winforms UI thread must be a single-threaded apartment thread.
Try:
[STAThread]
public static void Main()
{
Application.Run(new meow());
}
Note that ideally, you should just create your Winforms project using the template built into Visual Studio. It will configure the thread correctly for you.
I am writing a simple application that I would like to control with a notifyIcon rather than a form, I have follwed examples I found through Google, but my notifyIcon will not show up. What am I doing wrong?
static class MainEntryClass
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
C2F TestApp = new C2F();
Application.Run();
TestApp.Dispose();
}
}
class C2F
{
public C2F()
{
InitializeComponent();
loadSettings();
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(C2F));
this.niC2F = new System.Windows.Forms.NotifyIcon(this.components);
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.separatorToolStripMenuItem = new System.Windows.Forms.ToolStripSeparator();
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.contextMenuStrip1.SuspendLayout();
//
// niC2F
//
this.niC2F.BalloonTipText = "MyApp";
this.niC2F.Icon = ((System.Drawing.Icon)(Clipboard2File.Properties.Resources.ResourceManager.GetObject("MyIcon.ico")));
this.niC2F.Text = "MyApp";
this.niC2F.ContextMenuStrip = this.contextMenuStrip1;
this.niC2F.ShowBalloonTip(5);
this.niC2F.Visible = true;
this.niC2F.MouseClick += new System.Windows.Forms.MouseEventHandler(this.niC2F_MouseClick);
//
// contextMenuStrip1
//
this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.settingsToolStripMenuItem,
this.separatorToolStripMenuItem,
this.exitToolStripMenuItem});
this.contextMenuStrip1.Name = "contextMenuStrip1";
this.contextMenuStrip1.Size = new System.Drawing.Size(153, 76);
//
// settingsToolStripMenuItem
//
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
this.settingsToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.settingsToolStripMenuItem.Text = "Settings";
this.settingsToolStripMenuItem.Click += new System.EventHandler(this.settingsToolStripMenuItem_Click);
//
// separatorToolStripMenuItem
//
this.separatorToolStripMenuItem.Name = "separatorToolStripMenuItem";
this.separatorToolStripMenuItem.Size = new System.Drawing.Size(149, 6);
this.separatorToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
//
// exitToolStripMenuItem1
//
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem1";
this.exitToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
this.exitToolStripMenuItem.Text = "Exit";
}
private System.ComponentModel.IContainer components = null;
private Form1 frmSettings = new Form1();
private Settings C2FSettings = new Settings();
private System.Windows.Forms.NotifyIcon niC2F;
private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem;
private System.Windows.Forms.ToolStripSeparator separatorToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
}
I actually just finished a project that started as a NotifyIcon. Your code (I'm guessing you just provided a snippet) is incredibly similar to mine.
I checked your code, and the only change I had to make to get it to work was changing the way you called the icon to:
this.niC2F.Icon = new System.Drawing.Icon(#"C:\PathToIcon\iconfile.ico");
Below is a working sample with a right-click menu and double-click functionality:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace TestApp
{
static class MainEntryClass
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
C2F TestApp = new C2F();
Application.Run();
}
}
class C2F
{
System.ComponentModel.Container component;
System.Drawing.Icon icon;
ContextMenuStrip rightClickMenu = new ContextMenuStrip();
NotifyIcon trayIcon;
ToolStripMenuItem options = new ToolStripMenuItem();
ToolStripMenuItem restore = new ToolStripMenuItem();
ToolStripMenuItem exit = new ToolStripMenuItem();
ToolStripSeparator seperator = new ToolStripSeparator();
public C2F()
{
InitializeComponent();
}
private void InitializeComponent()
{
icon = new System.Drawing.Icon(#"C:\PathToIcon\iconfile.ico");
component = new System.ComponentModel.Container();
trayIcon = new NotifyIcon(component);
trayIcon.Text = "Bill Reminder";
trayIcon.Icon = icon;
trayIcon.Visible = true;
trayIcon.DoubleClick += new EventHandler(trayIcon_DoubleClick);
trayIcon.ContextMenuStrip = rightClickMenu;
rightClickMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[]
{
options,
seperator,
restore,
exit
});
options.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
options.Text = "Options";
options.Click += new EventHandler(options_Click);
restore.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
restore.Text = "Restore Window";
restore.Click += new EventHandler(restore_Click);
exit.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
exit.Text = "Exit";
exit.Click += new EventHandler(exit_Click);
}
void exit_Click(object sender, EventArgs e)
{
Application.Exit();
}
void restore_Click(object sender, EventArgs e)
{
FormName showWindow = new FormName();
showWindow.Show();
}
void options_Click(object sender, EventArgs e)
{
Settings_Window settings = new Settings_Window();
settings.Show();
}
void trayIcon_DoubleClick(object sender, EventArgs e)
{
FormName showWindow = new FormName();
showWindow.Show();
}
}
}
Hope this helps you, let me know if you have any questions!
One more reason why NotifyIcon is not shown is if Windows Explorer is running with elevated privileges while your tray application isn't (only on systems with UAC of course).
This can happen if explorer.exe crashed or was killed, and then user manually restarted it from the elevated Task Manager.
NotifyIcon control uses Shell_NotifyIcon native method inside, but doesn't check for the return value. If Shell_NotifyIcon returns FALSE, you won't be ever notified.
I had to breakpoint with WinDbg on Shell_NotifyIcon and GetLastError gave me ERROR_ACCESS_DENIED. So I realized that there's a permission issue, and it might be caused by restarted explorer elevation. Further tests confirmed this assumption.
However this is rather rare case.