I am tryig to fade-in a windows form using c# but it doesnt seem to work after I have shown the form. Is it possible to change the forms opacity after Ive shown it?
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;
using System.Timers;
namespace ToolStrip
{
public partial class Form1 : Form
{
Form ToolForm = new ToolForm();
Form PropForm = new PropertyGrid();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ToolForm.FormBorderStyle = FormBorderStyle.FixedToolWindow;
ToolForm.Owner = this;
ToolForm.Show();
ToolForm.Location = new Point(50, 50);
}
private void button2_Click(object sender, EventArgs e)
{
PropForm.FormBorderStyle = FormBorderStyle.FixedToolWindow;
PropForm.Owner = this;
PropForm.Show();
PropForm.Location = new Point(50, 50);
System.Timers.Timer aTimer = new System.Timers.Timer(10000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 2000;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
PropForm.Opacity = PropForm.Opacity - 0.25;
Console.WriteLine(PropForm.Opacity);
}
}
}
because you r using System.Timers.Timer which is a multithread timer, in it's OnTimedEvent() it calls control created by another thread, which cause exception.
If you use System.Windows.Forms.Timer, it will work. i tested.
Using your code (and creating the other necessary Form classes), I get a cross-threading exception the first time the timer fires and the event handler is called, as Benny suggests.
Making changes to your code to check InvokeRequired in the timer event handler, and use Invoke if necessary to change PropForm.Opacity, results in the opacity changing after the form is shown, as required.
Note that you probably want to start with an Opacity of 0, and increase it gradually - otherwise your form will start off completely solid and gradually fade out
I will mention in passing that Opacity will have no effect on some versions of Windows, though you say you have Opacity effects working elsewhere, so it shouldn't be that in this case.
Ive gotten it to work without timers:
int Loop = 0;
for (Loop = 100; Loop >= 5; Loop -= 10)
{
this.PropForm.Opacity = Loop / 95.0;
this.PropForm .Refresh();
System.Threading.Thread.Sleep(100);
}
but i cant seem to change this example to fade-in instead of out.
Related
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using Xamarin.Forms;
namespace TimerTest
{
public partial class MainPage : ContentPage
{
Label label;
int i = 0;
private static System.Timers.Timer aTimer;
public MainPage()
{
InitializeComponent();
label = new Label
{
Text = ""+i,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};
this.Content = label;
SetTimer();
//this.Content = label;
}
public void SetTimer()
{
// Create a timer with a two second interval.
aTimer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private async void OnTimedEvent(Object source, ElapsedEventArgs e)
{
i++;
label.Text = ""+i;
//this.Content = label;
}
}
}
I have followed Microsoft's definition for implementing the timer method, however, When trying to actually implement it, nothing is ever updated to the screen.
Below I have set up a simple program in Xamarin.Forms that should update the label to the count of whatever i is every 2 seconds, however, the screen just sits at 0 (what the label was initiated to).
Does anyone have any understand what I am doing wrong and how to fix my issue?
Thanks in advance!
You are not on the UI thread as the Timer callback is on a background thread, use Device.BeginInvokeOnMainThread when updating UI elements in that case:
So when updating your label instance in the callback, do this:
Device.BeginInvokeOnMainThread(() => label.Text = "" +i;);
If I were to update the text and update another element, would I just place a , after label.Text = ""+1or would I have to have a whole other line replicated,
The parameter provided to BeginInvokeOnMainThread is an Action, so you can execute as much code as needed on the UI thread using just one "block":
Device.BeginInvokeOnMainThread(() =>
{
...;
...;
...;
});
Or:
void UIThreadAction()
{
...;
...;
...;
}
Device.BeginInvokeOnMainThread(UIThreadAction);
This question already has answers here:
How do I update the GUI from another thread?
(47 answers)
Closed 5 years ago.
I recently started learning C#, I am trying to repeat a method every minute with help of a timer. The method changes the value of the label. However, I get the following error:
$exception {"Cross-thread operation not valid: Control 'label1'
accessed from a thread other than the thread it was created
on."} System.Exception {System.InvalidOperationException}
I have tried searching for a solution and each thread confuses me. I don't just need the correct code but also explanation as I want to learn manipulating UI with help of Timers and Threading.
The following is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Timers;
using System.Windows.Forms;
namespace Winforms_Timer_and_Thread
{
public partial class Form1 : Form
{
System.Timers.Timer myTimer = new System.Timers.Timer();
public Form1()
{
myTimer.Enabled = true;
InitializeComponent();
}
public void startMethod(object senter, ElapsedEventArgs e)
{
int cntr = 0;
cntr++;
label1.Text = "Executed: " + cntr.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "Started!";
myTimer.Enabled = true;
myTimer.Interval=(1*60*1000);
myTimer.Elapsed += new System.Timers.ElapsedEventHandler(startMethod);
}
}
}
If you change to use a System.Windows.Forms.Timer, you won't have that problem, since it's executed in the same UI thread.
You only have to change:
The type of the timer from System.Timers.Timer to System.Windows.Forms.Timer
The event that gets subscribed to from Elapsed to Tick
The event signature, where ElapsedEventArgs e becomes EventArgs e
You also only need to subscribe to the event once, not each time the timer is enabled, so move that to the Form_Load event instead, along with the Interval assignment (although that can be changed any time).
You also might want to store the counter variable outside of the StartMethod, so it increments each time it's executed, and then reset it to zero each time you start the timer:
public partial class Form1 : Form
{
readonly System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
private int tickCounter;
public Form1()
{
InitializeComponent();
myTimer.Interval = (int)TimeSpan.FromMinutes(1).TotalMilliseconds;
myTimer.Tick += StartMethod;
}
private void StartMethod(object sender, EventArgs e)
{
tickCounter++;
label1.Text = "Number of executions: " + tickCounter;
}
private void button1_Click(object sender, EventArgs e)
{
tickCounter = 0;
label1.Text = "Started!";
myTimer.Enabled = true;
}
}
I have created a Windows Forms Console Application in which I am reading a file which has been written by another console application.
The other console application will write about the status of some process and the Windows Forms application will read the status and accordingly update the status text box.
I wrote the following code for above scenario.
while (true)
{
if ((new FileInfo(filename)).Length > 0)
{
Status = File.ReadAllText(filename, Encoding.ASCII);
System.IO.File.WriteAllText(filename, string.Empty);
Statustb.Text = Status;
Statustb.Refresh();
if (Status.Equals("Data Got Loaded"))
{
Environment.Exit(0);
}
}
}
When I am running the Windows Forms application it shows "Form Not Responding" but when I comment out these lines then it will run smoothly. But for me it is important to update the status.
You have to understand the architecture of a GUI application.
All interactions with the user happen on one thread.
This includes reacting to things like mouse and keyboard events etc.
If one of these events happens you can handle that event and do something in response to it.
But, until you return from the handler, the application will not be able to receive any further notifications (Windows Messages aka events).
I suspect you have the above code in either the constructor or in one or other event handler. Since you never exit (infinite loop, due to while(true) without a return or break, the operating system cannot send any further events to the application. They get put in a queue to be sent, but never get picked up.
Windows will detect this situation and give you the Not Responding dialog message.
I suggest, that, instead of having the code inside the while(true) loop, you create a Timer with a suitable Interval, and put the body of the while statement (ie the bit between the { and }, but not the while(true) itself ) in the Tick handler.
It is better to use the code inside a timer.
Still, you need to make sure that no two different threads at the same time accessing a file. You should have used lock while reading and writing it.
I have a pattern that I use for getting long running tasks off of the UI thread. To see it, create a Winforms project and open the code-behind for Form1.cs. Delete the content and copy the following into that file. It should run and it has comments describing what it is doing.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace POC_DoEvents_alternate
{
public partial class Form1 : Form
{
private Button button1;
private Button button2;
private TextBox textbox1;
public Form1()
{
InitializeComponent();
// programmatically create the controls so that the
// entire source code is contained in this file.
// normally you wouldn't do this.
button1 = new Button();
button1.Name = "button1";
button1.Enabled = true;
button1.Location = new Point(12, 12);
button1.Size = new Size(144, 35);
button1.Text = "button1";
button1.Click += button1_Click;
this.Controls.Add(button1);
button2 = new Button();
button2.Name = "button2";
button2.Enabled = false;
button2.Location = new Point(12, 53);
button2.Size = new Size(144, 35);
button2.Text = "button2";
button2.Click += button2_Click;
this.Controls.Add(button2);
textbox1 = new TextBox();
textbox1.Name = "textbox1";
textbox1.Location = new Point(12, 94);
textbox1.ReadOnly = true;
textbox1.Size = new Size(258, 22);
this.Controls.Add(textbox1);
this.Load += new System.EventHandler(this.Form1_Load);
}
private void Form1_Load(object sender, EventArgs e)
{
textbox1.Text = "You can't press button 2 yet...";
button1.Enabled = true;
button2.Enabled = false;
this.Cursor = Cursors.AppStarting;
// start the long running task in a separate background thread
ThreadPool.QueueUserWorkItem(Async_LongRunningTask, "Form1_Load");
// calling the QueueUserWorkItem will not block. Execution will
// contiune immediately with the lines below it.
textbox1.BackColor = Color.LightPink;
// this event handler finishes quickly so the form will paint and
// be responsive to the user.
}
private void button1_Click(object sender, EventArgs e)
{
textbox1.Text = "Button 1 pressed";
}
private void button2_Click(object sender, EventArgs e)
{
textbox1.Text = "Button 2 pressed";
}
private void Async_LongRunningTask(object state)
{
// put all your long running code here, just don't put any
// UI work on this thread
Thread.Sleep(5000); // simulates a long running task
// put any UI control work back on the UI thread
this.Invoke((MethodInvoker)delegate
{
button2.Enabled = true;
textbox1.Text = "End of long running task: " + state.ToString();
textbox1.BackColor = SystemColors.Control;
this.Cursor = Cursors.Default;
// as with anything on the UI thread, this delegate
// should end quickly
});
// once the delegate is submitted to the UI thread
// this thread can still do more work, but being a
// background thread, it will stop when the application
// stops.
Thread.Sleep(2000); // simulates a long running task
}
}
}
You can add using System.Windows.Forms;
Application.DoEvents();
in the While
I am interested in checking the content of a website, the content changes frequently and when I view the website on any browser, it refreshes itself every 30 seconds. I want to know when the content has changed.
I am using winforms and I want to just click a button to start a loop, every 30 seconds. I don't want to hit the website too frequently, in fact the web pages own refresh is more than enough for my needs.
My code works when I click a button (btnCheckWebsite), if I wait a minute and then click btnCheckWebsite again, my message box pops up because the web page has changed. This is great however I want to do this in a while loop. When I un-comment my while loop, the DocumentText never changes. I have debugged it and for some reason it's the same text every time, even when the web page has changed in the real world, it stays the same in my code.
So my question is why can't I use a loop and what can I do instead to run this repeatedly without any input from me?
As a bonus, I would like to remove the .Refresh() I added this because it won't work without it however as I understand it, this refreshes the whole page. When I use a browser I see the page updating even when I don't refresh the whole page.
Just for background info, I did start by having a WebBrowser control on my form, the page refreshes automatically. I used the same code and have the same problem, interestingly, the WebBrowser control on my windows form refreshes by itself no problem, until I click btnCheckWebsite and then it stops refreshing! Also I know about webrequest but I don't know how to use it for my purposes.
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;
using System.Threading;
namespace Check_Website
{
public partial class Form1 : Form
{
public WebBrowser _memoryWebBrowser = new WebBrowser();
String _previousSource = "emptySource";
public Form1()
{
InitializeComponent();
_memoryWebBrowser.Navigate(new Uri("http://www.randomurl.com/"));
}
private void btnCheckWebsite_Click(object sender, EventArgs e)
{
//I want to un-comment this while loop and let my code run itself but it stops working
//when I introduce my while loop.
//while (1 < 2 )
//{
//Thread.Sleep(30000);
checkWebsite();
//}
}
private void checkWebsite()
{
//Why do I need this refresh? I would rather not have to hit the web page with a refresh.
//When I view the webpage it refreshed with new data however when I use a WebBrowser
//the refresh just doesn't happen unless I call Refresh.
_memoryWebBrowser.Refresh();
Thread.Sleep(500);
while (((_memoryWebBrowser.ReadyState != WebBrowserReadyState.Complete) || (_memoryWebBrowser.DocumentText.Length < 3000)))
{
Thread.Sleep(1000);
}
String source = _memoryWebBrowser.DocumentText;
if ((source != _previousSource) && (_previousSource != "emptySource"))
{
//Hey take a look at the interesting new stuff on this web page!!
MessageBox.Show("Great news, there's new stuff on this web page www.randomurl.co.uk!!" );
}
_previousSource = source;
}
}
}
You'd need to do your processing upon DocumentCompleted event. This event is asynchronous, so if you want to do this in a loop, the execution thread must pump messages for this event to fire. In a WinFroms app, your UI thread is already pumping messages in Applicaiton.Run, and the only other endorsed way to enter nested message loop on the same thread is via a modal form (here's how it can be done, see in the comments).
Another (IMO, better) way of doing such Navigate/DocumentCompleted logic without a nested message loop is by using async/await, here's how. In the classic sense, this is not exactly a loop, but conceptually and syntactically it might be exactly what you're looking for.
You can catch the WebBrowser.Navigated Event to get notified when the page was reloaded. So you wouldn't need a loop for that. (I meant the ready loop)
Just navigate every 30 seconds to the page in a loop and in the Navigated Event you can check whether the site has changed or not.
You'd better hook up DocumentCompleted event to check its DocumentText property!
The WebBrowser Element is very buggy and has much overhead for your needs. Instead of that you should use WebRequest. Because you said you don't know how to use, here's an (working) example for you.
using System;
using System.Windows.Forms;
using System.Net;
using System.IO;
namespace Check_Website
{
public partial class Form1 : Form
{
String _previousSource = string.Empty;
System.Windows.Forms.Timer timer;
private System.Windows.Forms.CheckBox cbCheckWebsite;
private System.Windows.Forms.TextBox tbOutput;
public Form1()
{
InitializeComponent();
this.cbCheckWebsite = new System.Windows.Forms.CheckBox();
this.tbOutput = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// cbCheckWebsite
//
this.cbCheckWebsite.AutoSize = true;
this.cbCheckWebsite.Location = new System.Drawing.Point(12, 12);
this.cbCheckWebsite.Name = "cbCheckWebsite";
this.cbCheckWebsite.Size = new System.Drawing.Size(80, 17);
this.cbCheckWebsite.TabIndex = 0;
this.cbCheckWebsite.Text = "checkBox1";
this.cbCheckWebsite.UseVisualStyleBackColor = true;
//
// tbOutput
//
this.tbOutput.Location = new System.Drawing.Point(12, 35);
this.tbOutput.Multiline = true;
this.tbOutput.Name = "tbOutput";
this.tbOutput.Size = new System.Drawing.Size(260, 215);
this.tbOutput.TabIndex = 1;
//
// Form1
//
this.ClientSize = new System.Drawing.Size(284, 262);
this.Controls.Add(this.tbOutput);
this.Controls.Add(this.cbCheckWebsite);
this.Name = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
this.PerformLayout();
timer = new System.Windows.Forms.Timer();
timer.Interval = 30000;
timer.Tick += timer_Tick;
}
private void Form1_Load(object sender, EventArgs e)
{
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
if (!cbCheckWebsite.Checked) return;
WebRequest request = WebRequest.Create("http://localhost/check_website.html");
request.Method = "GET";
WebResponse response = request.GetResponse();
string newContent;
using (var sr = new StreamReader(response.GetResponseStream()))
{
newContent = sr.ReadToEnd();
}
tbOutput.Text += newContent + "\r\n";
if (_previousSource == string.Empty)
{
tbOutput.Text += "Nah. It's empty";
}
else if (_previousSource == newContent)
{
tbOutput.Text += "Nah. Equals the old content";
}
else
{
tbOutput.Text += "Oh great. Something happened";
}
_previousSource = newContent;
}
}
}
I am working on a project using Visual Studio(c#). I want to create a startup form when i install my application with a progress bar. And after progress bar completed this form should be hide and a new form should be open. can u help me about this problem?
Edit:
I've just made a sample application trying to use exactly the code that you've specified. It worked fine besides just one tweak:
Form1().Show(); should be new Form1().Show();
The only way this code does not execute is if you forgot to set timer1 to enabled state in design view which causes the code to never fire up.
Are you sure the code is firing up? have you done a break-point on this piece of code?
On a sidenote: timer1 is not on a separate thread so you don't need to use Invoke (you can see if you actually need it by looking InvokeRequired property of a control)
Suggested improvement: if you are not going to use Form2 again and judging from your code, it is likely you won't; perhaps you should call Close() on Form2 instead of Hide() and release the resources. I've had times when my application kept running in background because I hid the form but never closed it and application was on "exit when last window closes" which never happened.
So to be sure, here is the final code that does work on my machine:
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 WindowsFormsApplication1
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
//enable timer1 here or in designer
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
//disable timer1 first thing, otherwise it can end up ticking
//multiple times before you've had a chance to disable it
//if the timespan is really short
timer1.Enabled = false;
int d;
for (d = 0; d <= 100; d++)
progressBar1.Value = d;
Hide();
//create a new Form1 and then show it
new Form1().Show();
}
}
}
Create your form and add your progress bar
Set up event handlers on the parts of the form that should effect the progress bar
Update the progree bar to reflect the amount of work that is done
When the form is complete close it
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 WindowsFormsApplication1
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
int d;
for (d = 0; d <= 100; d++)
progressBar1.Value = d;
this.Hide();
Form1().Show();
timer1.Enabled = false;
}
}
}