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;
}
}
}
Related
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 want to get html code from website. In Browser I usually can just click on ‘View Page Source’ in context menu or something similar. But how can I automatized it? I’ve tried it with WebBrowser class but sometimes it doesn’t work. I am not web developer so I don’t really know if my approach at least make sense. I think main problem is that I sometimes get html where not all code was executed. Hence it is uncompleted. I have problem with e.g. this site: http://www.sreality.cz/en/search/for-sale/praha
My code (I’ve tried to make it small but runnable on its own):
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WebBrowserForm
{
internal static class Program
{
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
for (int i = 0; i < 10; i++)
{
Form1 f = new Form1();
f.ShowDialog();
}
// Now I can check Form1.List and see that some html is final and some is not
}
}
public class Form1 : Form
{
public static List<string> List = new List<string>();
private const string Url = "http://www.sreality.cz/en/search/for-sale/praha";
private System.Windows.Forms.WebBrowser webBrowser1;
public Form1()
{
this.webBrowser1 = new System.Windows.Forms.WebBrowser();
this.SuspendLayout();
this.webBrowser1.Dock = System.Windows.Forms.DockStyle.Fill;
this.webBrowser1.Name = "webBrowser1";
this.webBrowser1.TabIndex = 0;
this.ResumeLayout(false);
Load += new EventHandler(Form1_Load);
this.webBrowser1.ObjectForScripting = new MyScript();
}
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.Navigate(Url);
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)
{
// Final html for 99% of web pages, but unfortunately not for all
string tst = webBrowser1.Document.GetElementsByTagName("HTML")[0].OuterHtml;
webBrowser1.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
Application.DoEvents();
webBrowser1.Navigate("javascript: window.external.CallServerSideCode();");
Application.DoEvents();
}
}
[ComVisible(true)]
public class MyScript
{
public void CallServerSideCode()
{
HtmlDocument doc = ((Form1)Application.OpenForms[0]).webBrowser1.Document;
string renderedHtml = doc.GetElementsByTagName("HTML")[0].OuterHtml;
// here I sometimes get full html but sometimes the same as in webBrowser1_DocumentCompleted method
List.Add(renderedHtml);
((Form1)Application.OpenForms[0]).Close();
}
}
}
}
I would expect that in ‘webBrowser1_DocumentCompleted’ method I could get final html. It usually works, but with this site it doesn’t. So I’ve tried get html in my own code which should be executed in web site -> method ‘CallServerSideCode’. What is strange that sometimes I get final html (basically the same as if I do it manually via Browser) but sometimes not. I think the problem is caused because my script start before whole web site is rendered instead after. But I am not really sure since this kind of things are far from my comfort zone and I don’t really understand what I am doing. I’m just trying to apply something what I found on the internet.
So, does anyone knows what is wrong with the code? Or even more importantly how to easily get final html from the site?
Any help appreciated.
You should use WebClient class to download HTML page. No display control necessary.
You want method DownloadString
May be it will be helpful if you add calling of your external function to the end of the body and wrap it by Jquery "ondomready" function. I mean something like this:
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)
{
// Final html for 99% of web pages, but unfortunately not for all
string tst = webBrowser1.Document.GetElementsByTagName("HTML")[0].OuterHtml;
webBrowser1.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
HtmlElement body = webBrowser1.Document.GetElementsByTagName("body")[0];
HtmlElement scriptEl = webBrowser1.Document.CreateElement("script");
IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement;
element.text = "$(function() { window.external.CallServerSideCode(); });";
body.AppendChild(scriptEl);
}
}
[ComVisible(true)]
public class MyScript
{
public void CallServerSideCode()
{
HtmlDocument doc = ((Form1)Application.OpenForms[0]).webBrowser1.Document;
string renderedHtml = doc.GetElementsByTagName("HTML")[0].OuterHtml;
// here I sometimes get full html but sometimes the same as in webBrowser1_DocumentCompleted method
List.Add(renderedHtml);
((Form1)Application.OpenForms[0]).Close();
}
}
I'm trying to use the below code to show a Balloon notification. I've verified that it's being executed by using breakpoints. It's also showing no errors.
What should I do to debug this since it's not throwing errors and not showing the balloon?
private void showBalloon(string title, string body)
{
NotifyIcon notifyIcon = new NotifyIcon();
notifyIcon.Visible = true;
if (title != null)
{
notifyIcon.BalloonTipTitle = title;
}
if (body != null)
{
notifyIcon.BalloonTipText = body;
}
notifyIcon.ShowBalloonTip(30000);
}
You have not actually specified an icon to display in the task bar. Running your code in LINQPad, by simply adding notifyIcon.Icon = SystemIcons.Application before the call to ShowBalloonTip I was able to get the tip to be displayed. Also note that you should call Dispose when you are done with your NotifyIcon instance.
Matthew identified the issue, but I still struggled to put all the pieces together. So I thought a concise example that works in LINQPad as-is would be helpful (and presumably elsewhere). Just reference the System.Windows.Forms assembly, and paste this code in.
var notification = new System.Windows.Forms.NotifyIcon()
{
Visible = true,
Icon = System.Drawing.SystemIcons.Information,
// optional - BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info,
// optional - BalloonTipTitle = "My Title",
BalloonTipText = "My long description...",
};
// Display for 5 seconds.
notification.ShowBalloonTip(5000);
// This will let the balloon close after it's 5 second timeout
// for demonstration purposes. Comment this out to see what happens
// when dispose is called while a balloon is still visible.
Thread.Sleep(10000);
// The notification should be disposed when you don't need it anymore,
// but doing so will immediately close the balloon if it's visible.
notification.Dispose();
See the below source code.
using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
namespace ShowToolTip
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btBallonToolTip_Click(object sender, EventArgs e)
{
ShowBalloonTip();
this.Hide();
}
private void ShowBalloonTip()
{
Container bpcomponents = new Container();
ContextMenu contextMenu1 = new ContextMenu();
MenuItem runMenu = new MenuItem();
runMenu.Index = 1;
runMenu.Text = "Run...";
runMenu.Click += new EventHandler(runMenu_Click);
MenuItem breakMenu = new MenuItem();
breakMenu.Index = 2;
breakMenu.Text = "-------------";
MenuItem exitMenu = new MenuItem();
exitMenu.Index = 3;
exitMenu.Text = "E&xit";
exitMenu.Click += new EventHandler(exitMenu_Click);
// Initialize contextMenu1
contextMenu1.MenuItems.AddRange(
new System.Windows.Forms.MenuItem[] { runMenu, breakMenu, exitMenu });
// Initialize menuItem1
this.ClientSize = new System.Drawing.Size(0, 0);
this.Text = "Ballon Tootip Example";
// Create the NotifyIcon.
NotifyIcon notifyIcon = new NotifyIcon(bpcomponents);
// The Icon property sets the icon that will appear
// in the systray for this application.
string iconPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + #"\setup-icon.ico";
notifyIcon.Icon = new Icon(iconPath);
// The ContextMenu property sets the menu that will
// appear when the systray icon is right clicked.
notifyIcon.ContextMenu = contextMenu1;
notifyIcon.Visible = true;
// The Text property sets the text that will be displayed,
// in a tooltip, when the mouse hovers over the systray icon.
notifyIcon.Text = "Morgan Tech Space BallonTip Running...";
notifyIcon.BalloonTipText = "Morgan Tech Space BallonTip Running...";
notifyIcon.BalloonTipTitle = "Morgan Tech Space";
notifyIcon.ShowBalloonTip(1000);
}
void exitMenu_Click(object sender, EventArgs e)
{
this.Close();
}
void runMenu_Click(object sender, EventArgs e)
{
MessageBox.Show("BallonTip is Running....");
}
}
}
For the sake of future coders:
the [timeout] parameter is deprecated as of windows vista
See: C# NotifyIcon Show Balloon Parameter Deprecated
So you might as well just put 0 into the parameter for > Windows Vista. What's worse, comments on the linked answer suggests that the replacement for these balloons, toast notifications, were only introduced in Windows 8. So for poor old Windows 7 falling between two stools, with Vista < 7 < 8, we seem to be at the mercy of however long Windows wants to keep that balloon there! It does eventually fade away, I've noticed, but after some empirical testing I'm quite sure that parameter is indeed being ignored.
So, building on the answers above, and in particular taking the lambda functions suggested by #jlmt in the comments, here's a solution that works for me on Windows 7:
//Todo: use abstract factory pattern to detect Windows 8 and in that case use a toastnotification instead
private void DisplayNotificationBalloon(string header, string message)
{
NotifyIcon notifyIcon = new NotifyIcon
{
Visible = true,
Icon = SystemIcons.Application
};
if (header != null)
{
notifyIcon.BalloonTipTitle = header;
}
if (message != null)
{
notifyIcon.BalloonTipText = message;
}
notifyIcon.BalloonTipClosed += (sender, args) => dispose(notifyIcon);
notifyIcon.BalloonTipClicked += (sender, args) => dispose(notifyIcon);
notifyIcon.ShowBalloonTip(0);
}
private void dispose(NotifyIcon notifyIcon)
{
notifyIcon.Dispose();
}
Notes
I've put a TODO in there to write another implementation for Windows
8, as people are 50/50 now on Windows 7/8 so would be good to support
a newer functionality. I guess anyone else coding this for multiple
versions of windows should probably do the same, ideally. Or just
stop supporting 7 and switch to using ToastNotification.
I purposely defined the disposal in a function so I could debug and verify that the breakpoint was indeed being hit.
ShowBalloonnTip takes the number of milliseconds. 3 milliseconds might be too fast for you to even see. Try something more like 3000
You might need to pass a component model to the contructor. It's what I see in all the examples. Sorry been a long time since I've used it. See first answer here:
NotifyIcon not showing
Take a look at the example here http://msdn.microsoft.com/en-us/library/system.windows.forms.notifyicon.aspx
I see some distinct differences between it an your code, there are many pieces you're leaving out such as creating a ComponentModelContainer and passing that into the NotifyIcon's constructor.
In the designer i put backgroundworker and i have two events: Do Work and Progress Changed.
I used breakpoint and its getting inside the Do Work event but it never get into the Progress Changed event. Its never stop there like the event isnt working. Why the progrss changed event isnt working ?
This 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;
using Google.GData.Client;
using Google.GData.Extensions;
using Google.GData.Extensions.MediaRss;
using Google.GData.YouTube;
using Google.YouTube;
using System.Threading;
namespace YoutubeTesting
{
public partial class Form1 : Form
{
YouTubeRequestSettings settings;
YouTubeRequest request;
string devkey = "AI39si6xhSQXx95FTYIACWPfq-lLIphblgaReuz9z6VEjR1Q6YjrV6FRN2U6FN6P6-lGF2OYaUZhCVOKJ_MCk4o6kPeUszvf5A";
string username = "chocolade13091972#gmail.com";
string password = "password";
public Form1()
{
InitializeComponent();
worker.RunWorkerAsync();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void upload()
{
try
{
settings = new YouTubeRequestSettings("You Manager", devkey, username, password);
settings.Timeout = -1;
request = new YouTubeRequest(settings);
Video video = new Video();
video.Title = "test";
video.Tags.Add(new MediaCategory("Comedy", YouTubeNameTable.CategorySchema));
video.Keywords = "Comedy";
video.Private = false;
video.MediaSource = new MediaFileSource("d:\\VIDEO0037.3gp", "video/3gp");
request.Upload(video);
MessageBox.Show("Successfully Uploaded");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
upload();
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
textBox1.Text = e.ProgressPercentage.ToString();
}
}
}
You need to report the progress using worker.ReportProgress()
From MSDN:
If you need the background operation to report on its progress, you
can call the ReportProgress method to raise the ProgressChanged event.
The WorkerReportsProgress property value must be true, or
ReportProgress will throw an InvalidOperationException.
It is up to you to implement a meaningful way of measuring your
background operation's progress as a percentage of the total task
completed.
The call to the ReportProgress method is asynchronous and returns
immediately. The ProgressChanged event handler executes on the thread
that created the BackgroundWorker.
You have to set this.
backgroundWorker.WorkerReportsProgress = true;
Gets or sets a value indicating whether the BackgroundWorker can
report progress updates.
EDIT
If still not working checks whether you have bind the event properly in the designer code. Or just add something like below in your class.
backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.worker_ProgressChanged);
In your Upload method you have to report progress. Otherwise above event won't fire. Keep in mind that, it's not easy to report actual progress always.
Below is an example code for a DoWork method. Look at here if you want to see a complete example.
static void bw_DoWork (object sender, DoWorkEventArgs e)
{
for (int i = 0; i <= 100; i += 20)
{
if (_bw.CancellationPending) { e.Cancel = true; return; }
_bw.ReportProgress (i);
Thread.Sleep (1000); // Just for the demo... don't go sleeping
} // for real in pooled threads!
e.Result = 123; // This gets passed to RunWorkerCompleted
}
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.