I'm doing a project in Visual Studio 2013 using Windows Forms.
I have a couple of forms (LogIn, Meny, FakturaSokning (For now))
When you start the program you open the LogIn and when you log in you go to the Meny where you can open the FakturaSokning.
Now to the problem i have.
I have 2 comboBoxes named comboBoxFaktNr1 and comboBoxFaktNr2 and I'm trying to populate them with the FaktNr i get from a SQL server. I connect to the server with
MigrateDBFakturaEntities db = new MigrateDBFakturaEntities();
and get the relevent information whith
var t = db.Fakturor.OrderBy(z => z.FaktNr).ToList();
the first thing i tried was doing a foreach loop
foreach (var item in t)
{
comboBoxFaktNr1.Items.Add(item.FaktNr);
}
witch works but the problem with this was that it stopped responding untill it was done.
How can i have it eather fill the comboboxes in the background when opening the FakturaSokning Form and auto update the comboboxes when its done or do it when eather in the Meny or LogIn form?
If i missed some relative information tell me and i will try adding it as soon as possible.
You can try using the Backgroundworker which executes the operation on a seperate thread.
Backgroundworker MSDN
This seamd to have been the problem. Also the problem i had when trying to use it earlier was that i tried to make and use the worker manualy by code. But if i used the ToolBox and added a worker from there everything worked.
And this is the code i used in the DoWork
BackgroundWorker worker = sender as BackgroundWorker;
List<Fakturor> t = db.Fakturor.OrderBy(z => z.FaktNr).ToList();
foreach (var item in t)
{
comboBoxFaktNr1.Invoke((Action)(() =>
{
comboBoxFaktNr1.Items.Add(item.FaktNr);
}));
}
Related
Is there any way to clear all the data stored on the memory after logging out in such a way that it looks like the condition when the application is run for the first time?
In my Winform project, there are different user levels that have different access to different forms and different controls.
After I click the log out button, the previous settings remain.
Is there any way to reset everything back to zero without having to set the all the setting of each form and every control ?
I finally found the answer.
It was very simple.
Application.Restart();
It shuts down the application and starts a new instance immediately.
You might need to manually nullify static variables if any are being used to store data on logout click.
To delete cookies:
foreach (string cookieFile in Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Cookies)))
{
try
{
File.Delete(cookieFile);
}
catch (Exception)
{
}
}
Scenario: I have configured Grid 2 and multiple tests are now running in parallel. When test starts there is opened browser window (only one tab opened) and some controls filled inside it. After that I open another tab (in the same browser window), switch to it and fill some controls inside it.
Before filling data inside second tab there needs to be done following steps:
1. Open new tab by calling SendKeys(Keys.Ctrl + 't')
2. Before switching to second tab wait for that second tab's handle to be added to driver instance.
3. If handle added to driver instance then switch to it, else 4.
4. Repeat operation 2. and 3. until timeout reached.
Problem:
When debugging I noticed that when opening a new tab, it's handle was not added to driver.WindowHandles. That means, if not checking if handle added and trying to switch to it, the exception will be thrown. In my case it would switch to incorrect tab as I'm calling driver.SwitchTo().Window(handles[handles.Count() -1]);. So I created method that waits for handle to be added. The problem is that, when running in multiple workers, it always times out. I have changed the timeout but nothing changes. The newly opened tab's handle is not added to WindowHandles. If I'm not running in parallel, then it works as expected.
// previousTabCount- browser's tab count before opening new one
public void WaitForTabToOpenAndSwtich(int previousTabCount)
{
int currentTabCount = driver.WindowHandles.Count();
int count = 0;
while(currentTabCount == previousTabCount)
{
// after 20 seconds throw exception
if(count > 20)
throw new Exception("The newly opened tab's handle was not added.");
// update current tab count
currentTabCount = driver.WindowHandles.Count();
count++;
Thread.Sleep(1000);
}
var handles = driver.WindowHandles;
driver.SwitchTo().Window(handles[handles.Count() -1]);
}
I found the solution. The problem was that when using SendKeys(Keys.Ctrl + 't') to open new tab on remote machine it did not work I'm not sure why. Fortunately I found an alternative approach. Instead of using that send keys command I used:
// script that opens a new tab
driver.ExecuteScript("var w = window.open(); w.document.open();");
After running this script the new tab was opened but I could not change its url by using driver.Navigate().GoToUrl("..."); and exception was thrown:
The HTTP request to the remote WebDriver server for URL 'http:
//example.com' timed out after 60 seconds
So I modified that script a bit by adding a page load at the end like this:
// script that opens new tab and reloads it
driver.ExecuteScript("var w = window.open(); w.document.open(); w.location.reload();");
This worked for me. Maybe someone will find this useful.
I have a DatGrid, which is bound to var Result_Full = new ObservableCollection<IP_DataRow>(). This is a simple class containing several string & double variables. Nothing difficult.
What I do, is that I read an Excel File (with Telerik RadSpreadProcessing), which parses rows into my class. I do this on a thread so that the UI is not blocked. I have encountered a few problems though:
1) I cannot use ref keyword in a long process which reads excel file (because Result_Full is a public property bound to a DataGrid), but I have to create temporary ObservableCollection<IP_DataRow>(), where the values are placed. Once the process has finished I run the following script for copying the values:
foreach (var item in tmpFull)
{
InvokeOnUIThread(() =>
{
Result_Full.Add(item);
});
}
What I would like to do, is to be able to see in a real time (if possible) how items are being added to the collection in my DataGrid.
As I am using .Net 4.5 I tried to implement BindingOperations.EnableCollectionSynchronization as was suggested by some other post, yet I could not figure out how to bind my UI bould collection Result_Full to temporary used in a process.
2) Even with the current setup, when (under my UI) I move to my Tab which contains DataGrid (my DataGrid is on a different TabPage), and I try to add new item to the collection with the above mentioned code, it returns an error saying: The calling thread cannot access this object because a different thread owns it., which is rather weird, as InvokeOnUIThread is nothing else but Dispatcher.Invoke(), which should be thread safe?
Any help would be highly appreciated.
EDIT: Showing more code:
This is the process I call from BackgroundWorker:
public void ProcessFile()
{
var tmpError = new ObservableCollection<IP_DataRow>();
var tmpFull = new ObservableCollection<IP_DataRow>();
var _reader = new IP_ExcelReader(sExcelPath, ref tmpError, ref tmpFull);
string sResult = _reader.ReadExcelFile();
if (sResult != string.Empty)
{
System.Windows.MessageBox.Show("Error processing selected Excel File!" + Environment.NewLine + Environment.NewLine + "Error message:" + Environment.NewLine + sResult);
}
foreach (var item in tmpError)//populates error list
{
IP_InvokeOnUIThread(() =>
{
Result_Error.Add(item);
});
}
foreach (var item in tmpFull)//populates full list
{
IP_InvokeOnUIThread(() =>
{
Result_Full.Add(item);
});
}
OnPropertyChanged("Result_Full");
//OnPropertyChanged("Result_Error");
iSelectedTabIndex = 1;
}
Here you can see, that I have to create temporary collection tmpError, tmpFull where I gather my data. At the end of process, I manually copy values into my main collections bound to DataGrid. I would like to change this, meaning that values are copied to the main collection (not temporary ones) during the process, so that user can see in a real time how values are added to the collection.
P.S.2:
for uknown reason to me, one of the problems lied in my InvokeOnUIThread call. Once I changed from App.Current.Dispatcher.Invoke(action); to App.Current.Dispatcher.BeginInvoke(action); error with ..different thread owns it stopped.
You can use BackgroundWorker instead of thread, to report progress as it goes.
Here is a simple tutorial
I believe that simply calling Dispatcher will use thread of a context, which is not UI-thread in your case. Try Application.Current.Dispatcher instead
In short, I believe you should do the following:
Create public ObservableCollection in UI-thread and bind it to DataGrid
Create a background worker. Set reporting to true. Subscribe to ReportProgress and DoWork events.
Run worker async
In DoWork handler create a list and read some amount of values to it. As you reach some amount, let's say a hundred, call (sender as BackgroundWorker).ReportProgress method, passing in event args this collection you have populated.
In report progress handler, populate your ObservableCollection from a list you've passed throught event args.
Steps 4 - 5 are repeated until everything is done
I am working on a Windows application. I have created a help file (.chm) using a third party tool and I call it from the Windows application. The help file is invoked successfully when I click on Help menu item or press F1 for the application.
The problem I am facing is that if I click on the menu item again or press F1 (while the application is open and I have not closed the previous help file) it opens another instance of the help file.
Let me be clear by giving an example: I want it to be just like the "Solitaire" game. No matter how many times you press F1 or the Contents menu item it shows only one help window.
I want to do same thing like "Solitaire". I don't want multiple instances to be created.
I hope you understood my problem. Please let me know if my query is wrong.
I have posted my code below.
ProcessStartInfo info;
Process exeprocess;
The below code is in Help menuitem click event.
private void mnuContents_Click(object sender, EventArgs e)
{
string ApplicationPath=ConfigurationSettings.AppSettings["HelpFile"].ToString();
info = new ProcessStartInfo(ApplicationPath);
//Process.Start(info);
exeprocess = Process.Start(info);
}
One solution is:
Have your application create a system-wide resource (the example below uses a Win32 mutex)
Check the resource before you spawn the .chm (I imagine you're probably using ShellExec or some variant to spawn the help file.
Here's example code (in C++/Win32 code):
http://support.microsoft.com/kb/243953
Another, different approach is to see if any currently running processes match the one you would spawn. Here's example code for this approach:
http://www.dotnetperls.com/single-instance-windows-form
You have a Process object, so you should probably store it somewhere and check if it is still active the next time the help command is invoked. You could use Process.HasExited for that purpose. If it has exited, clean up the Process object by calling Dispose() and then launch a new instance, storing it away again. Repeat as needed.
Ok this is your block of code to start the CHM viewer:
private void mnuContents_Click(object sender, EventArgs e)
{
string ApplicationPath=ConfigurationSettings.AppSettings["HelpFile"].ToString();
info = new ProcessStartInfo(ApplicationPath);
//Process.Start(info);
exeprocess = Process.Start(info);
}
in exeprocess there is a property called Id. You need to keep track of that Id for the next time the user presses F1 or the menu key.
You need to do a check like
private void mnuContents_Click(object sender, EventArgs e)
{
if (Process.GetProcessById(self.previousId) != null) {
string ApplicationPath=ConfigurationSettings.AppSettings["HelpFile"].ToString();
info = new ProcessStartInfo(ApplicationPath);
//Process.Start(info);
exeprocess = Process.Start(info);
self.previousId = exeprocess.Id;
}
}
Something like that would work. If you want to get fancy, you can bring the already-running process to the foreground as well.
I'm creating an application that uses .Net and Mono, it uses cross-threaded forms as I was having bad response from the child windows.
I created a test program with 2 forms: the first (form1) has a single button (button1) and the second (form2) is blank, code snippet below.
void openForm()
{
Form2 form2 = new Form2();
form2.ShowDialog();
}
private void button1_Click(object sender, EventArgs e)
{
Thread x = new Thread(openForm);
x.IsBackground = true;
x.Start();
}
This works fine in .Net, but with Mono, the first window will not gain focus when you click it (standard .ShowDialog() behaviour) rather than .Show() behaviour as .Net uses.
When I use .Show(), on .Net and Mono the window just flashes then disappears. If I put a 'MessageBox.Show()' after 'form2.Show()' it will stay open until you click OK.
Am I missing something in that code or does Mono just not support that? (I'm using Mono 2.8.1)
Thanks in advance, Adrian
EDIT: I realised I forgot 'x.IsBackground = true;' in the code above so child windows will close with the main window.
It's almost never the right thing to do in a Windows app to have more than one thread talk to one window or multiple windows which share the same message pump.
And it's rarely necessary to have more than one message pump.
The right way to do this is either to manually marshal everything back from your worker threads to your Window, using the 'Invoke' method, or use something like BackgroundWorker, which hides the details for you.
In summary:
Don't block the UI thread for time-consuming computation or I/O
Don't talk to the UI from more than one thread.
If you use Winforms controls, you shold "touch" the object always in main UI thread.
And at least - calling new Form.ShowDialog() in new thread does not make sense.
EDIT:
If you want easy work with Invoke/BeginInvoke you can use extension methods:
public static class ThreadingExtensions {
public static void SyncWithUI(this Control ctl, Action action) {
ctl.Invoke(action);
}
}
// usage:
void DoSomething( Form2 frm ) {
frm.SyncWithUI(()=>frm.Text = "Loading records ...");
// some time-consuming method
var records = GetDatabaseRecords();
frm.SyncWithUI(()=> {
foreach(var record in records) {
frm.AddRecord(record);
}
});
frm.SyncWithUI(()=>frm.Text = "Loading files ...");
// some other time-consuming method
var files = GetSomeFiles();
frm.SyncWithUI(()=>{
foreach(var file in files) {
frm.AddFile(file);
}
});
frm.SyncWithUI(()=>frm.Text = "Loading is complete.");
}