Recognition issue for window in different thread (tafx) - c#

We are trying to use Testing Automation FX for automating the basic workflow and testing in our application. The record function otherwise works flawlessly except in one specific case where the Windows Form in question is started from a different thread.
I noticed that the map generates an indistinguishable parent for the form in our application. The form is of type UIWindow and the following is the designer code for same.
this.uiWindow2.Comment = null;
this.uiWindow2.MatchedIndex = 0;
this.uiWindow2.MsaaName = null;
this.uiWindow2.MsaaRole = System.Windows.Forms.AccessibleRole.Client;
this.uiWindow2.Name = "uiWindow2";
this.uiWindow2.ObjectImage = ((System.Drawing.Bitmap)(resources.GetObject("uiWindow2.ObjectImage")));
this.uiWindow2.OwnedWindow = true;
this.uiWindow2.Parent = this.Application;
this.uiWindow2.UIObjectType = TestAutomationFX.UI.UIObjectTypes.Window;
this.uiWindow2.UseCoordinatesOnClick = true;
this.uiWindow2.WindowClass = "";
Since we don't have a parent window to our form, the only logical conclusion I could come up with was that windows was creating a wrapper around the form when it was started from a different thread.
What this does is that when tafx runs the test cases, it sometimes fails to find uiWindow2 or hooks onto some other window thus failing the test. This is totally random. I would like to know if there is a possible solution for this situation?
We are spawning window in a different thread using the following code snippet
private void LaunchBlottFormNewOnNewThread()
{
Form blottForm = new BlottForm();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(blotterForm);
}
private void StartBlott()
{
Thread blottThread = new Thread(new ThreadStart(LaunchBlottFormNewOnNewThread));
blottThread.SetApartmentState(ApartmentState.STA);
blottThread.Name = "BlottThread";
blottThread.IsBackground = true;
blottThread.Start();
}

Related

Why do I have to use the Application class to use WPF windows?

I create my Window class
class myWin : Window
{
public myWin()
{
Title = "My";
MaxWidth = 500;
MaxHeight = 500;
}
}
Why I can not run 'myWin' without run Application's instance?
Runs, but with freeze(Do not work).
myWin a = new myWin();
a.Show();
Works Perfectly!
myWin a = new myWin();
a.Show();
Application b = new Application();
b.Run();
I am using Xamarin Studio
The reason is that the Application class implements all the necessary plumbing/infrastructure to run a Windows application.
The main part is the management of the message pump which processes all the messages sent by the OS to the application, particularly the repaint events which trigger the ... repaint of the rendering surface of the application.
So what the Application.Run do is essentially starting the message pump.

STA threading exception in a Wpf application

I have a wpf application like this :
public CreateProject()
{
InitializeComponent();
_3DCAO.Temporary3DCAO.Close = false;
Userinitial fen = new Userinitial();
container.Content = fen;
Thread windowThread2 = new Thread(delegate() { verifing2(); });
windowThread2.IsBackground = true;
windowThread2.Start();
}
public void verifing2()
{
bool condition_accomplished = false;
while (!condition_accomplished)
{
if (Temporary3DCAO.Etape == 1)
{
_3DCAO.Settings set = new Settings();
if (container.Dispatcher.CheckAccess())
{
container.Content = set;
}
else
{
container.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
{
container.Content = set;
}));
}
condition_accomplished = true;
}
}
}
In the method Verifing i'd like to instanciate a User Control
_3DCAO.Settings set = new Settings();
But this error appears :
The calling thread must be STA, as required by many components of the user interface
Why this exception appears?
How can i fix it?
WPF (in fact all Windows GUI interactions) must have any GUI interaction on a single GUI thread, because the GDI (the subsystem which deals with the GUI in Windows) is single threaded. Everything must be on that thread. That thread is also an STA thread.
You're changing container, setting it's Content, and you're doing it on the wrong thread. There are ways to get it to the right thread.
In the constructor or after calling InitializeComponents(), add this
this.guiContext = SynchronizationContext.Current;
..where guiContext is of type System.Threading.SynchronizationContext. You can then despatch work onto the GUI thread:
guiContext.Send(this.OnGuiThread, temp);
Where OnGuiThread is a method taking as object parameter and temp is the object sent to it.
This will mean re-organising your code, as not only do you have to create GUI objects (like "set" in your code) on the thread, you can only change them on that thread.
Cheers -

How to access & use an object which has been created on a different thread in WPF

I am having following scenario that I need to show preview option in my application like what ms-word does. When we click the info option under File menu item, then preview of document is shown.
In the same way, I also want to show the preview of my data rendering part in my application when someone clicks File\Info panel. For this i have written a method which gets the preview or screenshots of my app but that method is taking some time So when somebody click on the File menu then application hangs for a while. So, i tried to call that method on different thread using background worker as well as normal thread mechanism. but the thing is that method I am calling on different thread it returns an image source object and when I try to access that object on run worker completed event of background worker, then it shows an exception like owner of this object is a different thread which means that returned image has been created on a different thread therefore I can't use it. So, what is the optimized way to get and use that image in my case.
Code tends to be like this.
public void ShowPreview()
{
ImageSource source =null;
var bgWorkerThread = new BackgroundWorker()
bgWorkerThread.DoWork +=(SENDER,ARGS)=> {
source = planView.GetPreviewImage();
}
bgWorkerThread.RunWorkerCompleted += (sender,args)=>
{
// Application crashes at this point
infoPanel.PreviewImage.source = args.Result as ImageSource;
}
}
you can use invoke or you could create a "storage class" (i think its called a singleton but I'm not sure) reuse the same instance across several classes and/or threads like this.
class Test
{
void main()
{
newThread nt = new newThread();
Storage store = new Storage();
nt.store = store;
Thread t = new Thread(new ThreadStart(nt.runMe));
t.Start();
}
}
public class newThread
{
public Storage store;
public void runMe()
{
store.someNum = 8;
}
}
public class Storage
{
public int someNum;
}

Single thread apartment issue

From my mainform I call the following to open a new form
MyForm sth = new MyForm();
sth.show();
Everything works great however this form has a combobox that, when I switch its AutoCompleteMode to suggest and append, I got this exception while showing the form:
Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it.
I have set this attribute on my main function as requested by the exception:
[STAThread]
static void Main(string[] args)
{ ...
Can I please get some help as to understand what might be wrong.
Sample code:
private void mainFormButtonCLick (object sender, EventArgs e)
{
// System.Threading.Thread.CurrentThread.SetApartmentState(ApartmentState.STA); ?
MyForm form = new MyForm();
form.show();
}
Designer:
this.myCombo.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.Suggest;
this.myCombo.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems;
this.myCombo.FormattingEnabled = true;
this.myCombo.Location = new System.Drawing.Point(20, 12);
this.myCombo.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.myCombo.Name = "myCombo";
this.myCombo.Size = new System.Drawing.Size(430, 28);
this.myCombo.Sorted = true;
this.myCombo.TabIndex = 0; phrase";
Setting data source
public MyForm(List<string> elem)
{
InitializeComponent();
populateColorsComboBox();
PopulateComboBox(elem);
}
public void PopulateComboBox(List<string> list )
{
this.myCombo.DataSource = null;
this.myCombo.DisplayMember = "text";
this.myCombo.DataSource = list;
}
Is Main(string[] args) really your entry point?
Maybe you have another Main() overload with no parameters. Or some other Main() in another class. Please open Project properties and look for the start object.
Windows Forms applications must be run in the STA method.
See here: Could you explain STA and MTA?
And COM comes into play since windows forms comes into play since the controls themselves use native windows handles and thus must adhere to the STA model. I do believe that the reason you get the error at this specific place is that a second thread is created/ used internally by the AutoCompletion.
And as far as I have expereienced, the threading model must be set in Main, changing it later only works from STA to MTA, but not the other way round
As a wild thought: Create a deep copy of your source List in your second form and bind the combobox to the copy of the list rather than the original.

Making a winforms 2.0 Splash Screen

What is the easiest way to fire a splash screen (Which disappears on its own) in a C# / .NET 2.0 winforms app? It looks like the VisualBasic assembly (which can be called from C# nonetheless) has a way to do this, but are there any simple examples?
Thanks
There's a detailed tutorial on Code Project which puts the splash screen on its own thread so the main app can get on with loading up.
Easiest way would be to create a form and allow it to kill itself after some time it is shown. But, things gets more complicated if you want this form to be able to display some application loading progress while application is initializing, and disappear for example 3 seconds after application is really ready for use.
Idea would include putting the splash screen on completely different thread from the main application. It's thread function should go like that:
static void ThreadFunc()
{
_splash = new Splash();
_splash.Show();
while (!_shouldClose)
{
Application.DoEvents();
Thread.Sleep(100);
if (new Random().Next(1000) < 10)
{
_splash.Invoke(new MethodInvoker(_splash.RandomizeText));
}
}
for (int n = 0; n < 18; n++)
{
Application.DoEvents();
Thread.Sleep(60);
}
if (_splash != null)
{
_splash.Close();
_splash = null;
}
}
Then, you can use this to show and hide it:
static public void ShowSplash()
{
_shouldClose = false;
Thread t = new Thread(ThreadFunc);
t.Priority = ThreadPriority.Lowest;
t.Start();
}
internal static void RemoveSplash()
{
_shouldClose = true;
}

Categories