Close form after raising an event - winforms

I have a mainform that opens a StartForm at some point:
private void TestChosen(object sender, TestChosenEventArgs e)
{
var frm = new TestStartForm(e.Test, StartTest);
frm.ShowDialog();
}
On this StartForm I have a button to actually start the test.
public TestStartForm(Test test, StartTestHandler startTestHandler)
{
InitializeComponent();
_test = test;
OnStartTest = startTestHandler;
}
public delegate void StartTestHandler(object sender, StartTestEventArgs e);
public event StartTestHandler OnStartTest;
public void InvokeOnStartTest(StartTestEventArgs e)
{
StartTestHandler handler = OnStartTest;
if (handler != null) handler(this, e);
}
private void btnStart_Click(object sender, EventArgs e)
{
InvokeOnStartTest(new StartTestEventArgs(_test));
Close();
}
The problem I'm facing is that the StartForm stays open untill the work of the StartTestHandler is completely done.
In the StartTestHandler another form is opened with the actual test.
Is there a way to force the StartForm to close without waiting for the test to be finnished?
EDIT
As #cowboydan suggested I've used BeginInvoke to show the form.However, I had to do it for the StartForm as well as the actual TestForm before it worked properly.
private void TestChosen(object sender, TestChosenEventArgs e)
{
BeginInvoke((Action)delegate
{
var frm = new TestStartForm(e.Test, StartTest);
frm.ShowDialog();
});
}
private void StartTest(object sender, StartTestEventArgs e)
{
BeginInvoke((Action)delegate
{
var frm = new TestForm(e.Test);
frm.ShowDialog();
});
}

You could use BeginInvoke which would launch StartForm in a separate thread from the ThreadPool. This is a fairly common practice.

Related

populating a listbox from another window, but on second attempt the list is replaced instead of added

I'm building a task list application.
From my main window, I click on the add button. The program generates a new Window,and I compete the form and close it with the complete button.
My listbox in the main window has been populated with the tasks that I have entered.
The problem is, when I do this again, the listbox items are replaced with new items instead of the ones being added.
MainWindow.cs
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
List<Task> allTasks = new List<Task>();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
private void addTaskBtn_Click(object sender, RoutedEventArgs e)
{
NewTaskWindow newTaskWindow = new NewTaskWindow();
newTaskWindow.Owner = this;
newTaskWindow.Show();
}
private void editTaskBtn_Click(object sender, RoutedEventArgs e)
{
}
private void searchBtn_Click(object sender, RoutedEventArgs e)
{
}
private void AddUserBtn_Click(object sender, RoutedEventArgs e)
{
}
private void markCompleteButton_Click(object sender, RoutedEventArgs e)
{
}
private void deleteTaskBtn_Click(object sender, RoutedEventArgs e)
{
}
}
NewTaskWindow.cs
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
namespace Task_Managment
{
public partial class NewTaskWindow : Window
{
Task newTask = new Task();
public NewTaskWindow()
{
InitializeComponent();
}
ObservableCollection<Task> AllTasks = new ObservableCollection<Task>();
ObservableCollection<Task> taskList = new ObservableCollection<Task>();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
string[] taskType = new string[3];
taskType[0] = "Home";
taskType[1] = "College";
taskType[2] = "Work";
CataCombo.ItemsSource = taskType;
}
public void completeBtn_Click(object sender, RoutedEventArgs e)
{
List<Task> allTasks = new List<Task>();
newTask = new Task
{
Title = titletxBx.Text,
Description = DesctxBx.Text,
Priority = prioritytxBx.Text,
Catagory = CataCombo.Text,
taskDate = calander.SelectedDate.Value
};
taskList.Add(newTask);
MainWindow main = Owner as MainWindow;
main.taskListBox.ItemsSource = taskList;
titletxBx.Clear();
prioritytxBx.Clear();
DesctxBx.Clear();
responsibilitytxBx.Clear();
}
private void finishBtn_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
}
You need to save the TaskList somewhere, make the tasklist definition public to get acces from the main window and pass it from the main window when you load the new form:
observableCollection<Task> AllTasks = new ObservableCollection<Task>();
public ObservableCollection<Task> taskList = new ObservableCollection<Task>();
public NewTaskWindow(ObservableCollection<Task> taskList)
{
InitializeComponent();
this.tasklist = tasklist
}
After that, you only need to retrieve and send it from the main to the new window
private void addTaskBtn_Click(object sender, RoutedEventArgs e)
{
NewTaskWindow newTaskWindow = new NewTaskWindow(tasklist);
newTaskWindow.Owner = this;
newTaskWindow.Show();
tasklist = newTaskWindow.tasklist;
}
In the main window you must initialize it for the first run if not you will get an error:
ObservableCollection<Task> taskList = new ObservableCollection<Task>();
public MainWindow()
{
InitializeComponent();
}
....
Obviously this only save for the time you have the program open, when you close the program it will lose all the info. So if you are interested in that also, save in a file and load from it.

Cannot set the value of a global variable

Im pretty new to programming, but im very eager to get more into this stuff, and in particular, c#. I have a made some code for an autotyper (spam bot if i may), only to be used as a goal for me to create. Essentially, what i want the program to do, is as following:
When i start my Form1, the global variable "_timerValue" is set to
1000
When i hit Start button, the text from the textbox on will be sent at
the interval of "_timerValue"
When i hit the Speed button, Form2 will show.
When i hit very fast, "_timerValue" is set to 5000 (testing purposes)
Form1 code:
public partial class Form1 : Form
{
static class TimerIntervalValue
{
Form2 f2 = new Form2();
TimerIntervalValue = f2._timerValue;
}
public Form1()
{
InitializeComponent();
f2._timerValue = "1000";
}
public void timer1_Tick(object sender, EventArgs e)
{
SendKeys.Send(textBox1.Text);
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Enabled = true;
}
private void button1_MouseDown(object sender, MouseEventArgs e)
{
MessageBox.Show(f2._timerValue);
timer1.Interval = Convert.ToInt32(f2._timerValue);
if (timer1.Enabled == false)
{
timer1.Enabled = true;
textBox1.Enabled = false;
button1.Text = ("Stop");
}
else if (timer1.Enabled == true)
{
timer1.Enabled = false;
textBox1.Enabled = true;
button1.Text = ("Start");
}
}
private void button2_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.Show();
}
}
Form2 code:
public partial class Form2 : Form
{
public string TimerValue;
public string _timerValue
{
get { return TimerValue; }
set { TimerValue = value; }
}
public Form2()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
Form2 frm2 = new Form2();
frm2._timerValue = "5000";
}
}
I originally tried to create a Form2 instance just under "InitializeComponent();" in Form1, but that didnt seem to be accessible through the other funtions.
I just know its something very simple like im using the wrong class to create the Form2 instance or something like that ...
Anyway, thank you in advance
Just mark TimerValue and _timerValue as static. Then you don't need to use
Form2 f2 = new Form2(); or Form2 frm2 = new Form2();
anymore. In Form 1, just use Form2._timerValue instead of f2._timerValue. In Form 2, just change:
public void button1_Click(object sender, EventArgs e)
{
_timerValue = "5000";
}

How can I update my WinForm label on timer?

I can't update my WinForm label properties.
Details: I am trying to check my database and get some values posted, but I can't even update a mere label it seems. I'm using SharpDevelop.
The code:
//this is my form
public partial class MainForm : Form
{
//Declaring timer
public static System.Timers.Timer aTimer = new System.Timers.Timer();
public MainForm()
{
InitializeComponent();
//Timer
aTimer.Elapsed +=new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 2000; //milisecunde
aTimer.Enabled = true;
label1.Text="some_text";
}
private static void OnTimedEvent(object source, ElapsedEventArgs e) {Check();}
public static void Check()
{
//Database checks here..
try{label1.Text="new_text";}catch(Exception e) {MessageBox.Show(e.ToString());}
MessageBox.Show("BAAAA");
}
void Button1Click(object sender, EventArgs e)
{
label1.Text = "mergeeeeee?!";
}
}
EDIT: I've removed all static modifiers. Also updated the post with the new code (try catch is added and the messagebox after it + a button that changes the label).
The try catches the following error:
. Really could use some help, been researching answers for more than 6 hours.
Try this (use a System.Windows.Forms.Timer instead of System.Timers.Timer):
//Declaring timer
public System.Windows.Forms.Timer aTimer = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
//Timer
aTimer.Tick += aTimer_Tick;
aTimer.Interval = 2000; //milisecunde
aTimer.Enabled = true;
label1.Text = "some_text";
}
void aTimer_Tick(object sender, EventArgs e)
{
Check();
}
public void Check()
{
try
{
//Database checks here..
label1.Text = string.Format("new_text {0}", DateTime.Now.ToLongTimeString());
}
catch (Exception ex)
{
throw ex;
}
MessageBox.Show("BAAAA");
}
The Elapsed event of the System.Timers.Timer is fired on a non-UI thread (change your original code to not swallow exceptions and you should see the cross-thread exception).
I used the following code for my project and it worked.
It has a button to activate the timer and the timer raises an event when 500 milliseconds passed.
private void ActiveTimer_Click(object sender, EventArgs e)
{
EnableTimer();
}
private void EnableTimer()
{
System.Timers.Timer raiseTimer = new System.Timers.Timer();
raiseTimer.Interval = 500;
raiseTimer.Elapsed += RaiseTimerEvent;
raiseTimer.AutoReset = true;
raiseTimer.Enabled = true;
}
private void RaiseTimerEvent(object sender, System.Timers.ElapsedEventArgs e)
{
this.Invoke(new Action(() =>
{
label1.Text += "500 ms passed\n";
}));
}

WPF Backgroundwork er call method on DoWork event

I have a BackgroundWorker on my WPF UserControl.
private readonly BackgroundWorker worker = new BackgroundWorker();
public ucCustomer()
{
InitializeComponent();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// run all background tasks here
System.Threading.Thread.Sleep(10000);
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//update ui once worker complete his work
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
worker.RunWorkerAsync();
}
Above code is work, the UI is response when the task is working, but if i change the worker_DoWork() to
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// run all background tasks here
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background,
new Action(() => {
gridDataBind(); //A long data-mining task,using Dispatcher.Invoke() to access UI.
}));
}
private void gridDataBind()
{
SnEntities sn = new SnEntities();
var customers = from c in sn.Customer select c;
dgCustomer.ItemsSource = customers.ToList();
}
The UI is freeze until the task is end.
Is it any solution?
Thanks you.
Try setting the ItemsSource like below code:
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// run all background tasks here
e.Result = gridDataBind(); //A long data-mining task.
}
private IList<Customer> gridDataBind()
{
SnEntities sn = new SnEntities();
var customers = from c in sn.Customer select c;
return customers.ToList();
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var customers = e.Result as IList<Customer>;
ObservableCollection<Customer> gridItemsSource = new ObservableCollection<Customer>();
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background,
new Action(() =>
{
dgCustomer.ItemsSource = gridItemsSource;
}));
foreach(var customer in customers)
{
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background,
new Action(() =>
{
gridItemsSource.Add(customer);
}));
}
}
Store your data in e.result at worker_DoWork and update UI at the worker_RunWorkerCompleted.
in that case UI will be free when data will coming from database.
Try this, it should help you
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => gridDataBind();));

New tab in WPF - items.add from buttons vs methods

OK, so I have a window called PictureWindow which displays pictures (I've cut out the code not related to making tabs). The TabControl is named "itemsTab". Using a button press, I can make a new tab no problem. But using the same operations inside a called method doesn't work. Using the buttonTab_Click method makes a new tab, the newTab method does not.
The only real difference I can see is due to the sender and RoutedEventArgs objects - how do these effect the operation here? Or is there something else I'm missing?
Thanks in advance.
Edit To make things even stranger, the newTab method does make a new tab, but only if it is called in the PictureWindow constructor method. If I have the following a new tab is made.
public PictureWindow(string current)
{
InitializeComponent();
newTab(current);
}
But if I call the method anywhere else it doesn't work.
public partial class PictureWindow : Window
{
public PictureWindow(string current)
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
private void buttonClose_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
private void buttonTab_Click(object sender, RoutedEventArgs e)
{
TabItem newTab = new TabItem();
newTab.Header = "New Tab!";
itemsTab.Items.Add(newTab);
}
public void newTab(string current)
{
TabItem newTab = new TabItem();
itemsTab.Items.Add(newTab);
}
}

Resources