How do I access the UI thread for my WCF subscriber? - winforms

I am currently developing a WCF Publish Subscribe service. The subscriber is a winform app. As the subscriber needs to implement the callback method for the service, which in my case is the PostReceived() method, and the publisher has the PublishPost() method.
For the PostReceived() method for my winform, it is unable to access the UI thread of my winform. The subscribe method is done on my main method. How do I program my PostReceived() method in such a way that it is able to access the labels and such of my mainForm?
EDIT
what I have tried so far is calling the mainForm object from my program.cs but it crashes when i run all 3 , stating the error that it is unable to access the UI thread.
EDIT 2
I have tried using the following code but there is an error for it.
mainForm b;
public void PostReceived(string postSampleData)
{
b.BeginInvoke((MethodInvoker)delegate()
{
b.lblSearch.Text = "lakjslkaja";
});
After running the code, there is an error of
Object reference not set to an instance of an object.
Any idea how to fix it?

Your PostReceived method should be something like this
void PostReceived()
{
yourform.BeginInvoke((MethodInvoker)delegate()
{
yourform.button.Text = "new label";
//More stuff here
});
}
This will guarantee that all the stuff after BeginInvoke is invoked in the UI thread.

Related

Rx reactive extensions Observeondispatcher unit test error: The current thread has no Dispatcher associated with it

I want to unit test a view model which contains a registration like:
public SampleViewModel(IUnityContainer container)
{
...
Observable.FromEventPattern<PropertyChangedEventArgs>(gridViewModel, "PropertyChanged")
.**ObserveOnDispatcher()**
.Subscribe(_ => this.Update());
...
}
When I run the unit test it tells me that "The current thread has no Dispatcher associated with it." when reaching this code.
One solution would be to use a Scheduler but I don't want to modify the Viewmodel.
Is there a solution to make the unit test pass this statement without getting an error?
I would suggest that you provide you own IScheduler implementation to ObserveOn(IScheduler) instead of using the ObserveOnDispatcher() operator. I have used techniques for loading a DispatcherFrame or a Dispatcher but the problem is that you are still using a Dispatcher. Eventually I found that you just "fall off the cliff" especially once you have long running background threads involved. Following the guidelines of "No threading in Unit tests" just dont let the dispatcher get near your ViewModels! Your Unit tests will run much, much faster.
A far superior way to deal with this is to inject an interface that gives access to your Dispatcher Scheduler (via the IScheduler interface). This allows you to substitute in an implementation that exposes the TestScheduler. You now can control time in your unit test. You can control and validate which actions are marshalled to each scheduler.
This is a really old (pre-Rx) post on 'Unit' testing WPF with Dispatcher calls from early 2009. It seemed like a good idea at the time.
https://leecampbell.com/2009/02/17/responsive-wpf-user-interfaces-part-5/
More information on Testing with Rx and the TestScheduler is found in my other site on Rx
http://introtorx.com/Content/v1.0.10621.0/16_TestingRx.html
This works for me.
When setting up the unit test I create an application to simulate the environment for my VM:
static Application App;
static void BeforeTestRun()
{
var waitForApplicationRun = new ManualResetEventSlim();
Task.Run(() =>
{
App = new Application();
App.Startup += (s, e) => { waitForApplicationRun.Set(); };
App.Run();
});
waitForApplicationRun.Wait();
}
and this is how I use it to instanciate the view model.
App.Dispatcher.Invoke(() => { this.viewModel = new ViewModel(); });
To properly unit test your viewmodel, you really need to be able to supply all of its dependencies. In this case, your viewmodel has a dependency upon the dispatcher. Making your viewmodel take a IScheduler dependency is the ideal way. But if you really don't want to do that, then try looking at this duplicate question: Unit test IObservable<T> with ObserveOnDispatcher
I found a solution for avoiding the error, simply from Unit Test code instantiate the ViewModel by using a dispatcher like:
SampleViewModel sampleViewModel;
var dispatcher = Application.Current != null ? Application.Current.Dispatcher : Dispatcher.CurrentDispatcher;
dispatcher.Invoke((Action)(() => sampleViewModel = new SampleViewModel(this.container);
That's all and seems to work without modifying current code, maybe there are also better solutions.

Launching a CustomAction UI written with WPF from a WIX installer: Fail on STAThread issue

My WIX installer launches an immediate custom action.
The custom action starts a WPF dialog prompting the user for a BD connection parameters (I basically wrote the 'new connection' DB prompter dialog in WPF, to get me a connection string that the custom action can inject in the installed application's configuration file).
The WIX code is fairly simple to figure out, and I know I execute the custom action just fine - I put there a MessageBox and a MmsiBreak on the call to my custom action method. I get there without a problem.
When the custom action instantiates my WPF dialog window, I get an InvaliOperationException: "The calling thread must be STA, because many UI components require this".
The same code runs fine when I put it in a standard WPF application, because VisualStudio generates boiler plate code with Main() that has a STAThreadAttribute on it.
I can't tack that attribute on the msiexec caller, and if I try to set the thread apartment state in my custom action, it fails:
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);
Is not supposed to work for framework past 2.0.
Is there any way to do what I'm trying to do here? I'd appreciate some pointers.
EDIT
I even tried to run the dialog in its own thread, e.g. the code is like this:
// Static class members
static ManualResetEvent _done = new ManualResetEvent(false);
static ActionResult _caResult;
static Session _session;
static Thread _worker;
[CustomAction]
static public ActionResult PromptForDB(Session session)
{
_session = session;
_worker = new Thread(WorkerThread);
_worker.Start();
_done.WaitOne();
return _caResult;
}
[STAThread]
static void WorkerThread()
{
try
{
Prompter wnd = new Prompter();
if (!(bool)wnd.ShowDialog())
{
_caResult = ActionResult.SkipRemainingActions;
}
else
{
// Harvest our properties (omitted from this post)
_caResult = ActionResult.Success;
}
catch (Exception ex)
{
_caResult = ActionResult.Failure;
_session.Log("Error: " + ex.Message);
}
finally
{
_done.Set();
}
}
That does not work either.
Before starting your new thread, set its ApartmentState as follows:
_worker.SetApartmentState(ApartmentState.STA);
See this:
The calling thread must be STA, because many UI components require this in WPF

Freeze WPF UI - multi-threading in view model class

Hi I use WPF with Caliburn Micro and in view model class I need test connection to SQL database.
Here is method which I use for testing connection.
public bool CheckSqlServer(string sqlHost, int sqlPort)
{
try
{
IPHostEntry ipHost = Dns.Resolve(sqlHost);
IPAddress ipAddr = ipHost.AddressList[0];
var tcpCli = new TcpClient();
tcpCli.Connect(ipAddr, sqlPort);
tcpCli.Close();
return true;
}
catch
{
return false;
}
}
And I call this method in another thread
//IP is worng
if (Task<bool>.Factory.StartNew(()=>CheckSqlServer("10.10.10.20",1521)).Result)
{
Insert();
}
Problem is that UI of WPF still freeze I dont know why because I call this method in new thread not in UI thread.
In your if you call Result straight away. That makes the calling thread wait on the task in a blocking way.
You should work e.g. with ContinueWith on the Task. That will be called once the execution of the first task finished. Careful with SynchronizationContext, though!
Also, you shouldn't call TaskFactory etc. in another thread. The whole point of Task is to abstract parallelism away from using the 'low-level' threads.
Try to set the proxy to null, so that the default auto-discovery will be disabled.
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.proxy.aspx

Exception while using ExecuteQuery() in Silverlight client object model

I have been developing a Silverlight user control for SharePoint using the Client Object model. Here is the coding
InitializeComponent();
ctx = ClientContext.Current;
Web web = ctx.Web;
ctx.Load(web, oweb => oweb.Title);
ctx.Load(web, oweb => oweb.Lists);
ctx.ExecuteQuery();
I heard tht SIlverlight supports both ExecuteQuery() and ExecuteQueryAsync() methods. But I'm getting an Exception message like this "he method or property that is called may block the UI thread and it is not allowed. Please use background thread to invoke the method or property, for example, using System.Threading.ThreadPool.QueueUserWorkItem method to invoke the method or property."
Can anyone tell me where am I going wrong and how to use ExecuteQuery() method ?? Thank you.
I might be off base here, but as I understand it, ExecuteQuery() requires you to create a thread so you aren't calling a stop to the UI thread when you invoke the method. The reason you use ExecuteQueryAsync is exactly that: ExecuteQueryAsync performs the operation on a seperate thread, then you just call back in to the UI thread using the dispather:
ctx.ExecuteQueryAsync(onQuerySucceeded, onQueryFailed);
...
private void onQuerySucceeded(object sender, ClientRequestSucceededEventArgs args)
{
this.Dispatcher.BeginInvoke((Action)(() =>
{
doStuff();
}));
}

WPF: How to handle errors with a BackgroundWorker

I am a bit of a newbie when it comes to windows client programming. I have a background worker that has a DoWork event and a RunCompleted event wired up. If an exception gets thrown in DoWork, I want to make changes to my UI, however, I cant because it is in a different thread. I can communicate the error to RunCompleted, but that doesn't help me either.
call Dispatcher.BeginInvoke. Basically, you want code like this:
void UpdateState(WhatEverType someObject)
{
if (! Dispatcher.CheckAccess())
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(()=>UpdateState(someObject));
}
else
{
//make the UI changes here.
}
}

Resources