I am building a Windows Forms App, where I created a UserControl (called MyControl).
This UserControl can generate and return a value using a BackgroundWorker.
My question is, how can my form1 show in real-time the value produced by the UserControl when the calculation is completed?
public partial class MyControl : UserControl
{
BackgroundWorker bgWorker;
private string _num;
public string Num
{
get
{
return _num;
}
set
{
_num = value;
}
}
public MyControl()
{
InitializeComponent();
bgWorker = new BackgroundWorker();
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
}
void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
//Done
MessageBox.Show(e.Result.ToString());
//↑↑↑↑↑ HERE
//I want to return to form1
// like to rewrite: form1.textbox1.text = e.Result.ToString();
});
btnStartAsyncOperation.Enabled = true;
btnCancel.Enabled = false;
}
void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
string Num = A_huge_calculation();
e.Result = Num;
}
private void RunCalculate(string Num)
{
if (bgWorker.IsBusy != true)
{
bgWorker.RunWorkerAsync(Num);
}
}
private void btnStartAsyncOperation_Click(object sender, EventArgs e)
{
RunCalculate(_num);
}
}
}
Why use BackgroundWorker? Because it will do an unpredictable thing(like generate the MD5 and SHA1 checksum for any file), and I don't wanna the main form fell asleep for end user.
Besides form2 will addition this UserControl like form1, and assign unique control to show the value.
form2.cs
public partial class Form2 : Form
{
MyControl mycontrol;
private void Form2_Load(object sender, EventArgs e)
{
mycontrol.SentTO = 'richtextBox1';
//It can be assign any container name to receive the value when completed.
//when trigger the execute button inside the MyControl
}
private void button1_Click(object sender, EventArgs e)
{
mycontrol = new MyControl();
mycontrol.Num = "xxxxxx";
//run mycontrol
//mycontrol.run();
richtextBox2.Text = mycontrol.value; //Here, when the MyControl calculation is completed.
}
}
I also have been thinking to set a timer listen to this user control get value every 1000ms.
form1.cs
private void timer1_Tick(object sender, EventArgs e)
{
if( ! string.IsNullOrEmpty(mycontrol.value))
{
richtextBox2.Text = mycontrol.value; //here is when the MyControl calculation is completed.
timer1.Stop();
}
}
The old ideal was to access the public value of MyControl by a timer,
when MyControl completed, it will return a non-null value, and the timer stop MyControl detection.
But it will derivative why the MyControl can know what is the timer name in form1?
Or form1 be set two or more MyControls, needs more timers to detect every MyControl.
Related
I want to display the current page-name that's on my WebBrowser control on my Label, but when the Document.Title updates, my label disappears instead of showing the current website title. How can i fix this?
public partial class StreamViewer : Form
{
public StreamViewer()
{
InitializeComponent();
webBrowserViewer.DocumentTitleChanged += new EventHandler(webBrowserViewer_DocumentTitleChanged);
}
private void webBrowserViewer_DocumentTitleChanged(object sender, EventArgs e)
{
label2.Text = webBrowserViewer.DocumentTitle;
}
Use the DocumentTitleChanged event
public Form1()
{
InitializeComponent();
webBrowserViewer.DocumentTitleChanged += new EventHandler(webBrowserViewer_DocumentTitleChanged);
}
private void webBrowserViewer_DocumentTitleChanged(object sender, EventArgs e)
{
label2.Text = webBrowser1.DocumentTitle;
}
https://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.documenttitlechanged(v=vs.110).aspx
I have created one loading form, but I want access the loading form and load the different form. I know there is a way to achieve this, but the way that I think is create another loading form and access that another loading form to load the different form, even though the loading form contents are same.
How can I achieve this?
Here is the code of Loading Form:
public Loading()
{
InitializeComponent();
this.timer1.Interval = SystemManager.RandomNumberGenerator(1000, 2000);
this.timer1.Tick += new EventHandler(this.CheckTimer);
}
private void Loading_Load(object sender, EventArgs e)
{
this.timer1.Start();
}
private void CheckTimer(object sender, EventArgs e)
{
uint timeLeft = 1;
timeLeft--;
if (timeLeft == 0)
{
this.timer1.Stop();
this.Hide();
AgeConfirmation _ageConfirmation = new AgeConfirmation();
_ageConfirmation.ShowDialog();
this.Close();
}
}
Above code is one loading form and load another form by the time is reached 0.
I have tried like this:
public class SystemManager
{
public static void LoadForm(Form _form = null, Form _loadForm = null)
{
_form.Hide();
_loadForm = new Form();
_loadForm.ShowDialog();
_form.Close();
}
}
and access it like this:
SystemManager.LoadForm(this, AgeConfirmation);
But it is throws the following error:
'System.Windows.Forms.AgeConfirmation' is a 'type' but is used like a 'variable'
My Question is: Create only one form (Loading Form), and access that Loading Form and by the time, the time reached 0, it will access different form.
Your answer much appreciated!
Thank you very much!
You should be using _ageConfirmation, which is the form object, not AgeConfirmation which is the form type.
i.e. SystemManager.LoadForm(this, _ageConfirmation);
Solved by myself! I create a getter and setter int value and by using switch case and the code will be like this:
public class UserInformation
{
public static int Value
{
get;
set;
}
}
public partial class Loading : Form
{
public Loading()
{
InitializeComponent();
this.timer1.Interval = SystemManager.RandomNumberGenerator(1000, 2000);
this.timer1.Tick += new EventHandler(this.CheckTimer);
}
private void Loading_Load(object sender, EventArgs e)
{
this.timer1.Start();
}
private void CheckTimer(object sender, EventArgs e)
{
uint timeLeft = 1;
timeLeft--;
if (timeLeft == 0)
{
this.timer1.Stop();
this.Hide();
switch (UserInformation.Value)
{
case 0:
AgeConfirmation _ageConfirmation = new AgeConfirmation();
_ageConfirmation.ShowDialog();
break;
case 1:
MainForm _mainForm = new MainForm();
_mainForm.ShowDialog();
break;
case 2:
Event _event = new Event();
_event.ShowDialog();
break;
}
this.Close();
}
}
}
private void AgeConfirmation_Load(object sender, EventArgs e)
{
UserInformation.Value = 1;
}
private void button1_Click(object sender, EventArgs e)
{
this.Hide();
Loading _loading = new Loading();
_loading.ShowDialog();
this.Close();
}
private void MainForm_Load(object sender, EventArgs e)
{
UserInformation.Value = 2;
}
private void button1_Click(object sender, EventArgs e)
{
this.Hide();
Loading _loading = new Loading();
_loading.ShowDialog();
this.Close();
}
By the time the program runs, UserInformation.Value will be 0
Thank you very much for those who are replying to my question.
Change
_ageConfirmation.ShowDialog();
to
_ageConfirmation.Show();
I am writing an application that passes gps data from a main form to a gps form at a constant interval (using a timer).
I've used the following tutorial to make a quick test:
http://www.codeproject.com/Articles/17371/Passing-Data-between-Windows-Forms
However, when I start the code no event is triggered. First I got a nullpointer. after adding the following lines I got rid of it:
if (GpsUpdated != null)
{
GpsUpdated(this, args);
}
Main form code:
public partial class Form1 : Form
{
// add a delegate
public delegate void GpsUpdateHandler(object sender, GpsUpdateEventArgs e);
// add an event of the delegate type
public event GpsUpdateHandler GpsUpdated;
int lat = 1;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Form_GPS form_gps = new Form_GPS();
form_gps.Show();
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
Debug.WriteLine("Timer Tick");
// instance the event args and pass it each value
GpsUpdateEventArgs args = new GpsUpdateEventArgs(lat);
// raise the event with the updated arguments
if (GpsUpdated != null)
{
GpsUpdated(this, args);
}
}
}
public class GpsUpdateEventArgs : EventArgs
{
private int lat;
// class constructor
public GpsUpdateEventArgs(int _lat)
{
this.lat = _lat;
}
// Properties - Viewable by each listener
public int Lat
{
get
{
return lat;
}
}
}
GPS form code:
public partial class Form_GPS : Form
{
public Form_GPS()
{
InitializeComponent();
}
private void Form_GPS_Load(object sender, EventArgs e)
{
Debug.WriteLine("GPS Form loaded");
Form1 f = new Form1();
// Add an event handler to update this form
// when the ID form is updated (when
// GPSUpdated fires).
f.GpsUpdated += new Form1.GpsUpdateHandler(gps_updated);
}
// handles the event from Form1
private void gps_updated(object sender,GpsUpdateEventArgs e)
{
Debug.WriteLine("Event fired");
Debug.WriteLine(e.Lat.ToString());
}
}
Can anyone point me in the right direction? What am I doing wrong?
Thanks in advance and with best regards.
You should pass an instance of Form1 to your Form_GPS for it to work properly. See the following changes:
public partial class Form_GPS : Form
{
public Form_GPS(Form1 owner)
{
InitializeComponent();
owner.GpsUpdated += new Form1.GpsUpdateHandler(gps_updated);
}
private void Form_GPS_Load(object sender, EventArgs e)
{
Debug.WriteLine("GPS Form loaded");
}
// handles the event from Form1
private void gps_updated(object sender,GpsUpdateEventArgs e)
{
Debug.WriteLine("Event fired");
Debug.WriteLine(e.Lat.ToString());
}
}
Now you need to a small change in Form1 as well:
private void Form1_Load(object sender, EventArgs e)
{
Form_GPS form_gps = new Form_GPS(this);
form_gps.Show();
timer1.Enabled = true;
}
Notice how you pass an instance of Form1 to Form_GPS in the constructor of Form_GPS using the self reference this.
Declaring the event as following solved the problem:
public static event GpsUpdateHandler GpsUpdated;
instead of:
public event GpsUpdateHandler GpsUpdated;
In this way the Form1 event can be called static, so no new instance is necessary.
I have a singletone form that can be opened from a ribbon button or that will check every minute whether it should be open after passing a few conditional checks.
When opening the form from the ribbon button, it works correctly every time.
When opening on the timer, the form does not get rendered correctly, any place a control should be is just displayed as a white rectangle. Screenshots below.
ThisAddIn.cs
using Timer = System.Timers.Timer;
public partial class ThisAddIn
{
private Timer ticker;
private void ThisAddIn_Startup(object sender, System.EventArgs e) {
ticker = new Timer(5 * 60 * 1000);
ticker.AutoReset = true;
ticker.Elapsed += new System.Timers.ElapsedEventHandler(checkForOverdue);
ticker.Start();
}
private void checkForOverdue(object sender, System.Timers.ElapsedEventArgs e)
{
bool overdue = false;
foreach (Reminder reminder in reminders)
{
DateTime now = DateTime.Now;
if (reminder.time <= now)
{
overdue = true;
break;
}
}
if (overdue)
{
RemindersList form = RemindersList.CreateInstance();
if (form != null)
{
form.Show();
}
}
}
}
Ribbon.cs
public partial class Ribbon
{
private void reminderListButton_Click(object sender, RibbonControlEventArgs e)
{
RemindersList form = RemindersList.CreateInstance();
if (form != null)
{
form.Show();
}
}
}
RemindersList.cs
public partial class RemindersList : Form
{
private static RemindersList _singleton;
private RemindersList()
{
InitializeComponent();
this.FormClosed += new FormClosedEventHandler(f_formClosed);
}
private static void f_formClosed(object sender, FormClosedEventArgs e)
{
_singleton = null;
}
public static RemindersList CreateInstance(List<Reminder> rs)
{
if (_singleton == null)
{
_singleton = new RemindersList(rs);
_singleton.Activate();
// Flash in taskbar if not active window
FlashWindow.Flash(_singleton);
return _singleton;
}
else
{
return null;
}
}
}
EDIT - SOLUTION
Per sa_ddam213's answer, I changed out the System.Timers.Timer for a Windows.Forms.Timer and it's now working just how I wanted.
Code changes:
ThisAddIn.cs
using Timer = System.Windows.Forms.Timer;
public partial class ThisAddIn {
private void ThisAddIn_Startup(object sender, System.EventArgs e) {
ticker = new Timer();
ticker.Interval = 5 * 60 * 1000;
ticker.Tick += new EventHandler(checkForOverdue);
ticker.Start();
}
// Also needed to change the checkForOverdue prototype as follows:
private void checkForOverdue(object sender, EventArgs e)
}
You can't touch UI controls/elements with any other thread than the UI thread, in your case the System.Timer is running on another thread and the window will never open
Try switching to a Windows.Forms.Timer
Or invoke the call back to the UI thread.
private void checkForOverdue(object sender, System.Timers.ElapsedEventArgs e)
{
base.Invoke(new Action(() =>
{
/// all your code here
}));
}
I suspect that the timer event handler is not launched on the UI thread, which could cause all sorts of problems. I would check that first and ensure that the UI stuff is actually done on the UI thread.
I have an app that show a form call System Parameters and i want the form to only pop one time so that the user cant open the same window million times. I tried
private void SystemParametersClick(object sender, EventArgs e)
{
Xpan sp = new Xpan();
sp.CurrentItem = this.GetCaller(sender);
if (sp.Visible==false)
{
sp.Show();
}
}
It doesnt work because it is not the same instance. :(
How do i make it only pop once?
Why do you instantiate the form within the method? Simply instantiate it within the parent class and only call the Show() method within the click event.
public class MainForm : Form
{
private Xpan _Xpan;
public MainForm()
{
InitializeComponent();
_Xpan = new Xpan();
}
private void SystemParametersClick(object sender, EventArgs e)
{
_Xpan.Show();
}
}
Maybe this simple approach would suffice?
private bool has_been_shown = false;
private void SystemParametersClick(object sender, EventArgs e)
{
if(!has_been_shown)
{
has_been_shown = true;
Xpan sp = new Xpan();
}
}
First disable closing for Xpan form. You can do it by defining OnFormClosing event handler.
private void Xpan_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
Hide();
}
Then define your Xpan form as a class member of the parent form, e.g.:
private readonly Xpan _sp = new Xpan();
And finally defile your Click handler this way:
private void SystemParametersClick(object sender, EventArgs e)
{
if (!_sp.Visible)
{
_sp.Show();
}
else
{
_sp.Activate();
}
}
That's it.