How can I test which icon my notifyIcon is using? - c#

I am having issues testing which icon my notifyIcon is using.
I have a notifyicon instantiated for my program. When the program runs I assign an icon to it in my code.
public Form1()
{
InitializeComponent();
notifyIcon1.Icon = Properties.Resources.LogoIcon;
}
I have 2 buttons, one which starts my timer, and 1 which stops my timer. The timer event is suppose to check which icon is currently being used and switch it to the other option, but it doesn't work using my test.
Timer miniClock = new Timer();
private void btnStartTimer_Click(object sender, EventArgs e)
{
miniClock.Interval = 1000;
miniClock.Tick += new EventHandler(MiniClockEventProcessor);
miniClock.Start();
}
private void MiniClockEventProcessor(Object myObject, EventArgs myEventArgs)
{
if (notifyIcon1.Icon == Properties.Resources.AlertIcon)
{
notifyIcon1.Icon = Properties.Resources.LogoIcon;
}
else
notifyIcon1.Icon = Properties.Resources.AlertIcon;
}
private void btnStopTimer_Click(object sender, EventArgs e)
{
miniClock.Stop();
btnTest.Enabled = true;
}
The frustrating part is when I start the timer, it will change the icon, but my test fails and it will only switch the icon in the else statement because there's no criteria to it except that it fails the if statement? How can I test which icon is currently being used, and then switch the icon to it's counterpart on the timer event call?

The reason is that every time you access an object directly from Properties.Resources, it actually reads it anew and creates a fresh object. Since == will test by reference and the references are not equal, your test fails each time.
The solution is to cache it, which you should be doing regardless for efficiency:
private static readonly Icon LogoIcon = Properties.Resources.LogoIcon;
private static readonly Icon AlertIcon = Properties.Resources.AlertIcon;
public Form1()
{
InitializeComponent();
notifyIcon1.Icon = LogoIcon;
}
and
Timer miniClock = new Timer();
private void btnStartTimer_Click(object sender, EventArgs e)
{
miniClock.Interval = 1000;
miniClock.Tick += new EventHandler(MiniClockEventProcessor);
miniClock.Start();
}
private void MiniClockEventProcessor(Object myObject, EventArgs myEventArgs)
{
if (notifyIcon1.Icon == AlertIcon)
{
notifyIcon1.Icon = LogoIcon;
}
else
notifyIcon1.Icon = AlertIcon;
}
private void btnStopTimer_Click(object sender, EventArgs e)
{
miniClock.Stop();
btnTest.Enabled = true;
}

I think it's easier to relay on some state then to Icon itself.
I imagine that yo setup AlertIcon or LogonIcon, based on some event, or on some changed state notification. It's better to have somewhere the simple bool statevariable that indicates what happens.
For example , to explain what am I talking about, is a pseudocode :
private void MiniClockEventProcessor(Object myObject, EventArgs myEventArgs)
{
if (!IsAlertState)
{
notifyIcon1.Icon = Properties.Resources.LogoIcon;
}
else
notifyIcon1.Icon = Properties.Resources.AlertIcon;
}
private bool IsAlertState {get;set}
On recived alert the property IsAlertState = true.
Something like this.

Related

How to loop asynchronously?

I get List of websites I need to loop through and to spend on each certain amount of time. Looping needs to be asynchronous, because on each website music will be played, and that's the main point - to hear the music in that amount of time, and then to load another page and to listen to its music and so on. Also, form need to be available for user actions.
Code I've got so far is this:
public void playSound(List<String> websites)
{
webBrowser.Navigate(Uri.EscapeDataString(websites[0]));
foreach (String website in websites.Skip(1))
{
StartAsyncTimedWork(website);
// problem when calling more times
}
}
private System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
private void StartAsyncTimedWork(String website)
{
myTimer.Interval = 7000;
myTimer.Tick += new EventHandler(myTimer_Tick);
myTimer.Start();
}
private void myTimer_Tick(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new EventHandler(myTimer_Tick), sender, e);
}
else
{
lock (myTimer)
{
if (this.myTimer.Enabled)
{
this.myTimer.Stop();
// here I should get my website which I need to search
// don't know how to pass that argument from StartAsyncTimedWork
}
}
}
}
One way to do this is as below.
Make websites a class field (if it isn't already), so the timer event handler can access this collection.
Add a field to keep track of the current index.
Add a field to prevent re-entrant calls to PlaySounds.
You're using a WinForms timer, which executes on the same thread as the form, so there's no need for InvokeRequired etc.
Some pseudo-code (warning, this is untested):
private bool isPlayingSounds;
private int index;
private List<String> websites;
private Timer myTimer;
private void Form1_Load()
{
myTimer = new System.Windows.Forms.Timer();
myTimer.Interval = 7000;
myTimer.Tick += new EventHandler(myTimer_Tick);
}
public void PlaySounds(List<String> websites)
{
if (isPlayingSounds)
{
// Already playing.
// Throw exception here, or stop and play new website collection.
}
else
{
isPlayingSounds = true;
this.websites = websites;
PlayNextSound();
}
}
private void PlayNextSound()
{
if (index < websites.Count)
{
webBrowser.Navigate(Uri.EscapeDataString(websites[index]));
myTimer.Start();
// Prepare for next website, if any.
index++;
}
else
{
// Remove reference to object supplied by caller
websites = null;
/ Reset index for next call to PlaySounds.
index = 0;
// Reset flag to indicate not playing.
isPlayingSounds = false;
}
}
private void myTimer_Tick(object sender, EventArgs e)
{
myTimer.Stop();
PlayNextSound();
}

dll: timer not firing

I have a dll that has a timer control in it, inside I have a message box. The timer has been enabled and the interval has been set to 100 seconds, but for some reason it's not firing. I added button to check if it's enabled, and timer1.enabled property is set to true, but it doesn't fire even once. Any ideas what could be wrong? Thanks!
Dll Code:
private void timer1_Tick(object sender, EventArgs e)
{
MessageBox.Show("Test");
}
This is how I call the dll form:
M.ModuleInterface module = Activator.CreateInstance(t) as M.ModuleInterface;
Thread t = new Thread(module.showForm);
t.Start();
showForm Method:
void M.ModuleInterface.showForm()
{
log("GUI::Initialized()");
frm.ShowDialog();
}
i believe, judging by your words alone, that you simply forgot to register to the time.
do:
public Form1()
{
InitializeComponent();
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
}
private void timer1_Tick(object sender, EventArgs e)
{
// Your code here
}
this little example works just fine:
private System.Windows.Forms.Timer timer1;
public Form1()
{
InitializeComponent();
timer1 = new System.Windows.Forms.Timer();
timer1.Interval = 100;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
timer1.Enabled = true;
}
private void Form1_Load(object sender, EventArgs e)
{
// timer is triggered. code here is called
}

Stopwatch changing button text in c#

Basically, I've got multiple button in my Form, and I want for it show a Stopwatch in the button.Text when the button is pressed. (Button is modified to be a toggle button.) and to stop and reset the timmer when the button is toggled off. Simple enough it seemed but because I have multiple buttons that could be pressed in any order, and I don't know anything about threading, this seems to be much more difficult that I presumed.
My origional intent was to have a function that constantly runs every second and interates a interager only if the button is pressed using this code:
public void Jogger()//purpose is to step up time[0] every second only when a button is on.
{
while (true)
{
for (int i = 0; i < 16; i++)
{
if (btnstat[i])
time[i]++;
}
Thread.Sleep(1000);
}
}
Problem is, I don't know threading so when I call the function, its stuck doing this and only this.
Either way, once this is called, all i do us call my update function that updates all the buttons including the button.Text which displays the time[0]; (array built around buttons)
Is their a better way of doing this that doesn't cause so much CPU use and/or simply works?
Thanks for all the help!
-John Ivey
Assuming you using checkbox with property Button = Appearence, in event handler for CheckedChanged:
private void CheckBoxCheckedChanged(object sender, EventArgs e)
{
CheckBox checkBox = (CheckBox) sender;
if (checkBox.Checked)
{
Timer timer = new Timer {Interval = 1000};
timer.Tick += Jogger;
timer.Start();
timer.Tag = new CheckboxCounter {CheckBox = checkBox, Time = 0};
checkBox.Tag = timer;
}
else
{
Timer timer = checkBox.Tag as Timer;
if (timer != null)
{
timer.Tag = null;
timer.Stop();
timer.Dispose();
checkBox.Tag = null;
}
}
}
Change your Jogger function:
private void Jogger(object a_sender, EventArgs a_eventArgs)
{
Timer timer = (Timer) a_sender;
CheckboxCounter data = (CheckboxCounter)timer.Tag;
data.Time++;
data.CheckBox.Text = data.Time.ToString();
}
You also need some simple class to store checkbox and current time:
class CheckboxCounter
{
public CheckBox CheckBox;
public int Time;
}
Then you can add any number of checkboxes and just set event CheckedChanged to CheckBoxCheckedChanged.
Try this out. After re-building or running, you should have the new "ButtonTimer" at the top of your ToolBox. Drop a couple on your Form, run it, and see what happens when you click them. Right click them to "Reset" them:
public class ButtonTimer : CheckBox
{
private System.Windows.Forms.Timer Tmr = new System.Windows.Forms.Timer();
private System.Diagnostics.Stopwatch SW = new System.Diagnostics.Stopwatch();
public ButtonTimer()
{
this.Tmr.Interval = 500;
this.Tmr.Tick += new EventHandler(tmr_Tick);
this.Appearance = System.Windows.Forms.Appearance.Button;
this.CheckedChanged += new EventHandler(ButtonTimer_CheckedChanged);
ContextMenuStrip cms = new ContextMenuStrip();
ToolStripItem tsi = cms.Items.Add("Reset");
tsi.Click += new EventHandler(tsi_Click);
this.ContextMenuStrip = cms;
}
protected override void OnLayout(LayoutEventArgs levent)
{
base.OnLayout(levent);
this.Text = TimeSpan.Zero.ToString(#"hh\:mm\:ss");
}
private void ButtonTimer_CheckedChanged(object sender, EventArgs e)
{
if (this.Checked)
{
this.SW.Start();
this.Tmr.Start();
}
else
{
this.SW.Stop();
this.Tmr.Stop();
}
}
private void tmr_Tick(object sender, EventArgs e)
{
this.UpdateTime();
}
private void UpdateTime()
{
this.Text = this.SW.Elapsed.ToString(#"hh\:mm\:ss");
}
private void tsi_Click(object sender, EventArgs e)
{
if (this.SW.IsRunning)
{
SW.Restart();
}
else
{
SW.Reset();
}
this.UpdateTime();
}
}
Application.DoEvents() for simplicity put inside loop . . but it is advisable to start to lean threading . you will just learn how to start thread and how make cross thread safe call
Next simple will be to use backgroundworker . look this http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
ok here is thread solution also as you wanted . Tested too . as a stop variable i used Tag. But u can inherit button to make state button.it be more clear way . And below code will use one thread per button . So u should make it in one thread to make it better solution . You can modify this code to do all checkings inside one thread . For this you start thread once can make delegate for attaching dinamically count function for each button or you can pass buttons before . With one word there are more than one way to do it. Good luck
this.button1.Click += new System.EventHandler(this.button_Click);
this.button2.Click += new System.EventHandler(this.button_Click);
...and so on
private void button_Click(object sender, EventArgs e)
{
Thread x= new Thread(new ParameterizedThreadStart(Jogger2));
x.Start(sender);
}
private void button_Click(object sender, EventArgs e)
{
Button mybtn=sender as Button;
if((string)mybtn.Tag=="start"){
mybtn.Tag ="";
return;
}
mybtn.Tag = "start";
Thread x= new Thread(new ParameterizedThreadStart(Jogger2));
x.Start(sender);
}
private bool setResult(object obj,string text)
{
if (this.textBox1.InvokeRequired)
{
Func<Button,string, bool > d = new Func<Button,string,bool >(setResult);
return (bool)this.Invoke(d,obj,text);
}
else
{
Button btn=obj as Button;
if (btn != null)
{
btn.Text = text;
if ((string)btn.Tag !="start") return false;
}
return true;
}
}
private void Jogger2(object mybtn)
{
int ii = 0;
while (true)
{
Thread.Sleep(1000);
//replace with your code
ii += 1;
if (!setResult(mybtn, ii.ToString())) break;
}
}

How to display a text on a RichTextBox char by char?

I have Form1, RichTextBox1 and Button1 on my Form
To understand what i'm trying to do; take a look at this link, type in a facebook profile link and click on Hack Account AND SEE THE GREEN TEXT THAT APPEARS
I'm using the code below in C# to achieve what i want to do :
private void button1_Click(object sender, EventArgs e)
{
string myStr = "This is a test string to stylize your RichTextBox1";
foreach (char c in myStr.ToCharArray()) {
Thread.Sleep(100);
richTextBox1.AppendText(c.ToString());
}
}
But it doesn't work, the text appears in the text box at one time; Not char by char!
The reason your code is showing all the text at once is using Thread.Sleep() keep the main Thread (the UI thread) suspended / sleep mode, so none of the Application message are processed on form & the form paint / drawing event are not doing the job as the UI thread is sleeping/suspended!
Solution 1: Use a helper Thread so that Thread.Sleep() dont make ur app go in non-responsive mode
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string myStr = "This is a test string to stylize your RichTextBox1";
ThreadPool.QueueUserWorkItem(ShowTextInInterval, myStr);
}
private void ShowTextInInterval(object state)
{
string mystr = state as string;
if (mystr == null)
{
return;
}
for (int i = 0; i < mystr.Length; i++)
{
AppendNewTextToRichTextBox(mystr[i]);
Thread.Sleep(100);
}
}
private delegate void app_char(char c);
private void AppendNewTextToRichTextBox(char c)
{
if (InvokeRequired)
{
Invoke(new app_char(AppendNewTextToRichTextBox), c);
}
else
{
richTextBox1.AppendText(c.ToString(CultureInfo.InvariantCulture));
}
}
}
Solution # 2 : Use a timer
public partial class Form1 : Form
{
private Timer tbTimer = new Timer();
string myStr = "This is a test string to stylize your RichTextBox1";
private int charPos = 0;
public Form1()
{
InitializeComponent();
tbTimer.Interval = 100;
tbTimer.Tick += TbTimerOnTick;
}
private void TbTimerOnTick(object sender, EventArgs eventArgs)
{
if (charPos < myStr.Length - 1)
{
richTextBox1.AppendText(myStr[charPos++].ToString(CultureInfo.InvariantCulture));
}
else
{
tbTimer.Enabled = false;
}
}
private void button1_Click(object sender, EventArgs e)
{
tbTimer.Enabled = true;
}
}
This is because the textbox is not refreshing whilst you are still running your code. Try putting this:
foreach (char c in myStr.ToCharArray()) {
Thread.Sleep(100);
richTextBox1.AppendText(c.ToString());
richTextBox1.Refresh();
}
The problem you are having is not in appending the text,
richTextBox1.AppendText(c.ToString()); //Good
works as expected but the issue is that you are putting the UI thread to sleep blocking the drawing of the text on the Rich Text Box.
Thread.Sleep(100); //Not so good
A quick workaround would be to add
richTextBox1.Refresh();
This forces the control to be redrawn after appending the text, but note your entire UI is still going to be frozen while the thread sleeping. A better solution maybe to use a System.Windows.Forms.Timer to accomplish your goal. This class triggers an event every specified interval. Some quick code,
private System.Windows.Forms.Timer TextUpdateTimer = new System.Windows.Forms.Timer();
private string MyString = "This is a test string to stylize your RichTextBox1";
private int TextUpdateCount = 0;
private void button1_Click(object sender, EventArgs e)
{
//Sets the interval for firing the "Timer.Tick" Event
TextUpdateTimer.Interval = 100;
TextUpdateTimer.Tick += new EventHandler(TextUpdateTimer_Tick);
TextUpdateCount = 0;
TextUpdateTimer.Start();
}
private void TextUpdateTimer_Tick(object sender, EventArgs e)
{
//Stop timer if reached the end of the string
if(TextUpdateCount == MyString.Length) {
TextUpdateTimer.Stop();
return;
}
//AppendText method should work as expected
richTextBox1.AppendText(MyString[TextUpdateCount].ToString());
TextUpdateCount++;
}
This updates the text box char by char without blocking the main thread and maintains usability on the front end.

C# - Make form semi-transparent while moving

Is there any way to make the form semi-transparent while it is being moved and then become opaque when it's not being moved anymore? I have tried the Form_Move event with no luck.
I'm stuck, any help?
The reason the form loads as semi-transparent is because the form has to be moved into the starting position, which triggers the Move event. You can overcome that by basing whether the opacity is set, on whether the form has fully loaded.
The ResizeEnd event fires after a form has finished moving, so something like this should work:
bool canMove = false;
private void Form1_Load(object sender, EventArgs e)
{
canMove = true;
}
private void Form1_Move(object sender, EventArgs e)
{
if (canMove)
{
this.Opacity = 0.5;
}
}
private void Form1_ResizeEnd(object sender, EventArgs e)
{
this.Opacity = 1;
}
To do it properly I expect you'd need to override the message processing to respond to the title bar being held, etc. But you could cheat, and just use a timer so that you make it opaque for a little while when moved, so continuous movement works:
[STAThread]
static void Main()
{
using (Form form = new Form())
using (Timer tmr = new Timer())
{
tmr.Interval = 500;
bool first = true;
tmr.Tick += delegate
{
tmr.Stop();
form.Opacity = 1;
};
form.Move += delegate
{
if (first) { first = false; return; }
tmr.Stop();
tmr.Start();
form.Opacity = 0.3;
};
Application.Run(form);
}
}
Obviously you could tweak this to fade in/out, etc - this is just to show the overall concept.

Categories