How do I get the value of NotifyIcon.Icon property programmatically? - c#

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

Related

How to disable the automatic selection of the first item in ComboBox?

I have a form with a ComboBox, which is populated with 3 items.
When I add the statements: comboBox1.Text = "A"; and comboBox1.DroppedDown = true;
the first item of the drop-down list is automatically selected: the comboBox1.Text shows "Abc" in stead of "A".
Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace testComboBox
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
comboBox1 = new ComboBox();
PopulateComboBox();
comboBox1.Location = new Point((this.Width - comboBox1.Width) / 2, 80);
this.Controls.Add(comboBox1);
comboBox1.Text = "A";
comboBox1.DroppedDown = true;
}
ComboBox comboBox1;
private void PopulateComboBox()
{
comboBox1.Items.Add("Abc");
comboBox1.Items.Add("Abcd");
comboBox1.Items.Add("Abcde");
}
private void button_Exit_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
How can I disable the automatic selection of the first item in the Items collection of the ComboBox, so that the comboBox1.Text will show "A" and not "Abc"?
I am not looking for a one-time work-around. I need a GENERAL SOLUTION.
set this code comboBox1.SelectedText = null;
public Form1()
{
InitializeComponent();
comboBox1 = new ComboBox();
PopulateComboBox();
comboBox1.Location = new Point((this.Width - comboBox1.Width) / 2, 80);
this.Controls.Add(comboBox1);
comboBox1.SelectedText = "A";
comboBox1.DroppedDown = true;
comboBox1.SelectedText = null;
}
With the help of the thread that Loathing pointed to, I copied the extension Class ComboBoxAutoSelectExtension and in the form I just added the line of code: ComboBoxAutoSelectExtension.AutoSelectOff(comboBox1);
If you copy the ComboBoxAutoSelectEx from the link in the comment, then the only thing you should have to do in your own Form1 code is:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
comboBox1 = new ComboBox();
String text = "A";
comboBox1.Text = text;
comboBox1.Select(text.Length,1); // put cursor at the end of text
ComboBoxAutoSelectEx.AutoSelectOff(comboBox1); // Added
PopulateComboBox();
comboBox1.Location = new Point((this.Width - comboBox1.Width) / 2, 80);
this.Controls.Add(comboBox1);
}
protected override void OnLoad(EventArgs e) { // Added
base.OnLoad(e);
comboBox1.DroppedDown = true;
}
ComboBox comboBox1;
private void PopulateComboBox()
{
comboBox1.Items.Add("Abc");
comboBox1.Items.Add("Abcd");
comboBox1.Items.Add("Abcde");
}
private void button_Exit_Click(object sender, EventArgs e)
{
this.Close();
}
}
I see no way to disable auto selection of an item. I can only replace the wrong selection with the input text that was previously known. This bug occurs on both opening or closing the dropdown. Here is an example code when opening the dropdown.
// record
box_txt = comboBox1.Text;
box_pos = comboBox1.SelectionStart;
// drop down
comboBox1.DroppedDown = true;
// replace
comboBox1.Text = box_txt;
comboBox1.SelectionStart = box_pos;

Program does not get text or set text

In my C# windows form project my program is not able to get the text from a text box, nor set the text box. I am able to register button clicks, so it seems that the programs GUI thread is okay.
private void sendButton_Click(object sender, EventArgs e)
{
Console.WriteLine("I am being pressed");
textBox2.Text = "Test";
this.Refresh();
}
As you can see from the code when the button is pressed the output panel says "I am being pressed". However, the text box does not visually update and say "Test".
Is there a reason why I am not able to set or get text. I have tried appending the text, but that is not my intention.
My guess is that the form is not focused perhaps, since I have changed what form is showing. The code below is from the first form class. lobby is a new Form that I show.
if (correct)
{
lobby lob = new lobby(client, this);
this.Hide(); // this is the first form the user sees, I have hidden it. If I close this form then the application exits.
lob.Show(); // this is the form that I show after the user logs in with right credentials. Textbox.text = "test" does not work on this for some reason.
}
In the first form window I am able to use the Text method and retrieve/set values.
But I cannot do the same in the second form.
--------Edit-------
This is the GUI builder for the second form.
You can see the name field is called "TextBox2".
lobby.cs file
using System.Net.Sockets;
using System.Windows.Forms;
namespace ClientMMO
{
public partial class lobby : Form
{
static int counter;
private Socket client;
private Form1 form1;
public lobby()
{
InitializeComponent();
}
public lobby(Socket client)
{
InitializeComponent();
this.client = client;
}
public lobby(Socket client, Form1 form1) : this(client)
{
InitializeComponent();
this.form1 = form1;
textBox2.Text = "Test";
}
}
}
lobby.Designer.cs
namespace ClientMMO
{
partial class lobby
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.textBox2 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(107, 90);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(251, 20);
this.textBox2.TabIndex = 0;
//
// lobby
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(511, 413);
this.Controls.Add(this.textBox2);
this.Name = "lobby";
this.Text = "lobby";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox textBox2;
}
}
This is the first form that the user sees. Everything works normal here, as it should.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;
using System.Xml.Serialization;
namespace ClientMMO
{
public partial class Form1 : Form
{
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
User test;
public Form1()
{
InitializeComponent();
ConnectToServer();
}
private void ConnectToServer()
{
IPAddress ipAddress = IPAddress.Loopback;
IPEndPoint ep = new IPEndPoint(ipAddress, 1234);
client.Connect(ep);
Console.WriteLine("connnected");
}
private void button1_Click(object sender, EventArgs e)
{
test = new User();
test.UserName = textBox1.Text;
test.Password = textBox2.Text;
client.Send(ClassToByteArray(test));
byte[] data = new byte[1024];
client.Receive(data);
string returndata = System.Text.Encoding.ASCII.GetString(data);
label1.Text = returndata;
//Console.WriteLine(returndata);
string b = "Logged in";
int result = 0;
string str1 = "Logged in";
result = string.Compare(str1, returndata);
if (result == 0)
{
button1.Visible = false;
byte[] shit = new byte[1024];
client.Receive(shit);
Console.WriteLine(shit.ToString());
string sfs = System.Text.Encoding.ASCII.GetString(shit);
label1.Text = String.Empty;
label1.Text = sfs;
int port = Int32.Parse(sfs);
client.Close();
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAddresse = IPAddress.Loopback;
IPEndPoint epe = new IPEndPoint(ipAddresse, port);
client.Connect(epe);
Console.WriteLine("connected to another server");
/*------------------------------------This is where I open up my new window --------------------*/
lobby lob = new lobby(client, this);
this.Hide(); // this is the first form the user sees, I have hidden it. If I close this form then the application exits.
lob.Show(); // this is the form that I show after the user logs in with right credentials. Textbox.text = "test" does not work on this for some reason.
}
else
{
label1.Text = "failed";
}
}
private byte[] ClassToByteArray(Object objClass)
{
try
{
MemoryStream ms = new MemoryStream();
XmlSerializer xmlS = new XmlSerializer(typeof(User));
XmlTextWriter xmlTW = new XmlTextWriter(ms, Encoding.UTF8);
xmlS.Serialize(xmlTW, objClass);
ms = (MemoryStream)xmlTW.BaseStream;
return ms.ToArray();
}
catch (Exception)
{
throw;
}
}
private Object ByteArrayToClass(byte[] buffer)
{
try
{
XmlSerializer xmlS = new XmlSerializer(typeof(User));
MemoryStream ms = new MemoryStream(buffer);
XmlTextWriter xmlTW = new XmlTextWriter(ms, Encoding.UTF8);
return xmlS.Deserialize(ms);
}
catch (Exception)
{
throw;
}
}
}
}
What you're doing should work, assuming you're starting your main form properly. You could try putting an Application.DoEvents() after setting the text property. Make sure you're not waiting on a semaphore or something.
Do you store lob as a class variable, rather than a local variable?
There is no answer for this, that I can give in terms of "fixing" the bug (If there is one).
But the solution was to create a new Windows form file and start again.
I don't think this is a bug. I think you are trying to access a private object from another form.
Write a new method in lobby.cs that sets the text of textBox1 like:
public void SetText(string text){
textBox2.Text = text;
}
Then when you are hiding the main Form:
lobby lob = new lobby(client, this);
this.Hide();
lob.SetText("Test");
lob.Show();

C# opening a Form out of a TrayIcon

i just used this snippet for creating a tray application with two buttons (settings and exit):
using System;
using System.Windows.Forms;
using System.Drawing;
using WindowsFormsApplication1;
//*****************************************************************************
abstract class NotIco
{
private static NotifyIcon notico;
//==========================================================================
public static void Main(string[] astrArg)
{
ContextMenu cm;
MenuItem miCurr;
cm = new ContextMenu();
miCurr = new MenuItem();
miCurr.Index = 0;
miCurr.Text = "&Settings";
miCurr.Click += new System.EventHandler(SettingsClick);
cm.MenuItems.Add(miCurr);
miCurr = new MenuItem();
miCurr.Index = 1;
miCurr.Text = "Beenden";
miCurr.Click += new System.EventHandler(ExitClick);
cm.MenuItems.Add(miCurr);
notico = new NotifyIcon();
notico.Icon = new Icon("tanss.ico");
notico.Text = "TANSS Busylight Connector";
notico.Visible = true;
notico.ContextMenu = cm;
notico.DoubleClick += new EventHandler(NotifyIconDoubleClick);
Application.Run();
}
//==========================================================================
protected static void ExitClick(Object sender, EventArgs e)
{
notico.Dispose();
Application.Exit();
}
//==========================================================================
protected static void SettingsClick(Object sender, EventArgs e)
{
/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>
// This should open the "Settings"-Popup, containing 3 textboxes and a button to save them to xml.
}
//==========================================================================
protected static void NotifyIconDoubleClick(Object sender, EventArgs e)
{
// ...
}
}
Now i want to open a new Form as a Popup containing 3 textboxes to write some values in and a button to save them.
In the background, a never ending loop is requesting a url and parsing a value out of a json.
could you help me opening the new form (its not made yet, i just need it to open first :/)
and where do i embedd my background loop-code?
thanks so much!
It is as simple as
MyForm form1 = new MyForm();
form1.Show();
You have to create a new form object and show it on screen.
and, if you want to, you can set all others properties
form1.Location = new Point(20, 20);
form1.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
form1.MaximizeBox = true;
form1.ControlBox = true;
......
I think is better (easier actually) to create the form from the designer and avoid the creation of every textbox and everything from code.

Variable not updating on closing a new pop up form after clicking button

I am trying to make a button that when clicked pops up a new form with a yes and no button and then make an if statement based on what button is pressed. Here is my current code:
private YesNoMessageBoxResized newBoxResized;
private string buttonClickResult;
public void YesNoNewMessageBox(string title, string message,string buttonYes, string buttonNo)
{
YesNoMessageBoxResized msgResized = new YesNoMessageBoxResized(title, message, buttonYes, buttonNo);
msgResized.StartPosition = FormStartPosition.CenterScreen;
msgResized.TopMost = true;
Button yesButtonResize = new Button();
Button noButtonResize = new Button();
//yes button
yesButtonResize.Text = buttonYes;
yesButtonResize.Size = new Size(150, 80);
yesButtonResize.Font = new Font("Arial", 26);
yesButtonResize.Location = new Point(100, 150);
//no button
noButtonResize.Text = buttonNo;
noButtonResize.Size = new Size(150, 80);
noButtonResize.Font = new Font("Arial", 26);
noButtonResize.Location = new Point(300, 150);
//make a copy of the current form
newBoxResized = msgResized;
//eventhandlers
yesButtonResize.Click += YesButtonResizeClicked;
noButtonResize.Click += noButtonResizeClicked;
newBoxResized.Controls.Add(yesButtonResize);
newBoxResized.Controls.Add(noButtonResize);
msgResized.Show();
}
private void YesButtonResizeClicked(object o, EventArgs sEA)
{
this.buttonClickResult = "true";
this.newBoxResized.Close();
}
private void noButtonResizeClicked(object o, EventArgs sEA)
{
this.buttonClickResult = "false";
this.newBoxResized.Close();
}
private void buttonRestoreDefaults_Click(object sender, EventArgs e)
{
YesNoNewMessageBox("Restore Defaults?", "Restore Defaults?", "Yes", "No");
if (this.buttonClickResult == "true")
this.restoreDefaults();
}
My problem is that after hitting yes and closing the form that pops up, buttonClickResult is not seen as true and therefore the restore default function I am calling is not called. Only when clicking on the "RestoreDefaults" button again is the function called. So, it seems that the onclick event for buttonRestoreDefaults_Click isn't reconizing the onclick for the yes or no buttons in the form that popups until clicking on it again. Is there a way around this or some sort of implementation to fix this? Thank you.
Also, here is the code for the class. I was thinking about using delegates and event handlers, but I am not sure if I actually need that since what I have works, but just doesn't update the variable on closing correctly:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class YesNoMessageBoxResized : Form
{
private Label labelMessage;
//no default button specified
public YesNoMessageBoxResized(string title, string message, string buttonYes, string buttonNo)
{
InitializeComponent();
this.Text = title;
this.labelMessage.Text = message;
this.Deactivate += MyDeactivateHandler;
}
public YesNoMessageBoxResized()
{
InitializeComponent();
}
private void InitializeComponent()
{
this.labelMessage = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// labelMessage
//
this.labelMessage.AutoSize = true;
this.labelMessage.Font = new System.Drawing.Font("Microsoft Sans Serif", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelMessage.Location = new System.Drawing.Point(12, 31);
this.labelMessage.Name = "labelMessage";
this.labelMessage.Size = new System.Drawing.Size(165, 29);
this.labelMessage.TabIndex = 3;
this.labelMessage.Text = "labelMessage";
//
// YesNoMessageBoxResized
//
this.ClientSize = new System.Drawing.Size(572, 268);
this.Controls.Add(this.labelMessage);
this.Name = "YesNoMessageBoxResized";
this.ResumeLayout(false);
this.PerformLayout();
}
protected void MyDeactivateHandler(object sender, EventArgs e)
{
this.Close();
}
public delegate void buttonYes_ClickResultEvent(object o, EventArgs sEA);
public event buttonYes_ClickResultEvent choiceResult;
}
public class buttonYes_ClickResultEvent : EventArgs
{
public buttonYes_ClickResultEvent(bool choice)
{
this.buttonResult = choice;
}
public bool buttonResult;
}
**I posted this on codereview, but then they told me to post it here since it deals with solving a problem.
just for a test, try using a global variable and set that to true within your yesbuttonresizedclicked event.
something like
public static bool yestest = false;
private void YesButtonResizeClicked(object o, EventArgs sEA)
{
yestest = true;
}
I sort of fixed it by adding a function that had the if statement withing the other button events. I am open to other solutions though:
private YesNoMessageBoxResized newBoxResized;
private string buttonClickResult;
public void YesNoNewMessageBox(string title, string message,string buttonYes, string buttonNo)
{
YesNoMessageBoxResized msgResized = new YesNoMessageBoxResized(title, message, buttonYes, buttonNo);
msgResized.StartPosition = FormStartPosition.CenterScreen;
msgResized.TopMost = true;
Button yesButtonResize = new Button();
Button noButtonResize = new Button();
//yes button
yesButtonResize.Text = buttonYes;
yesButtonResize.Size = new Size(150, 80);
yesButtonResize.Font = new Font("Arial", 26);
yesButtonResize.Location = new Point(100, 150);
//no button
noButtonResize.Text = buttonNo;
noButtonResize.Size = new Size(150, 80);
noButtonResize.Font = new Font("Arial", 26);
noButtonResize.Location = new Point(300, 150);
//make a copy of the current form
newBoxResized = msgResized;
//eventhandlers
yesButtonResize.Click += YesButtonResizeClicked;
noButtonResize.Click += noButtonResizeClicked;
newBoxResized.Controls.Add(yesButtonResize);
newBoxResized.Controls.Add(noButtonResize);
newBoxResized.Show();
}
private void YesButtonResizeClicked(object o, EventArgs sEA)
{
this.buttonClickResult = "true";
this.DoIfStatement();
this.newBoxResized.Close();
}
private void noButtonResizeClicked(object o, EventArgs sEA)
{
this.buttonClickResult = "false";
this.DoIfStatement();
this.newBoxResized.Close();
}
private void DoIfStatement()
{
if (buttonClickResult == "true")
this.restoreDefaults();
}
private void buttonRestoreDefaults_Click(object sender, EventArgs e)
{
YesNoNewMessageBox("Restore Defaults?", "Restore Defaults?", "Yes", "No");
}
I think I need it to be more modular though. I don't always want the same if statement there. So, I don't always want to be a yes and no with regards to restore defaults. I may want it to do something else with another function call and have yes and no buttons do something else.
You can just use MessageBox to do this for you:
if (MessageBox.Show("Yes or no?", "", MessageBoxButtons.YesNo)
== DialogResult.Yes)
You could change the form to a modal dialog form. Make the Accept and Cancel buttons properties equal the appropriate button. Then change the dialog result of each button to the appropriate value. Now when you use the ShowDialog the form will return the appropriate DialogResult.

How to change cursor in custom control?

Here is my custom WebBrowser control.
using System;
using System.Text.RegularExpressions;
using System.Windows.Forms;
public class RunescapeClient : WebBrowser
{
private const string RUNESCAPE_CLIENT_URL = "http://oldschool33.runescape.com/j1";
public RunescapeClient()
{
ScrollBarsEnabled = false;
ScriptErrorsSuppressed = true;
IsWebBrowserContextMenuEnabled = false;
AllowWebBrowserDrop = false;
Navigate(RUNESCAPE_CLIENT_URL);
}
protected override void OnDocumentCompleted(WebBrowserDocumentCompletedEventArgs e)
{
if (Document != null && ValidClientUrl(e.Url.ToString()))
{
HtmlElement tableElement = Document.GetElementsByTagName("table")[1];
tableElement.InnerText = string.Empty;
}
}
private static bool ValidClientUrl(string url)
{
return Regex.IsMatch(url, #"http://oldschool\d{1,2}.runescape.com/j1");
}
}
How can I change the cursor for this control to my embedded .ico. I googled and couldn't find anything for custom controls.
Thanks.
The cursor is always changed by the Cursor property. It doesn't matter if you have a custom control.
Try this:
Icon ico = new Icon(#"C:\temp\someIcon.ico");
this.Cursor = new Cursor(ico.Handle);
The static class System.Windows.Forms.Cursors contains all system cursors.
To switch back to the default system cursor, use this:
this.Cursor = System.Windows.Forms.Cursors.Default;

Categories