How to update gui in c# wpf from asynchronous method callback - c#

I've search on stackoverflow and also in net and I couldn't find solution to my problem.
I read from a stream in async way. I want callback to update gui
[STAThread]
private void ClientLoggedCallback(IAsyncResult res)
{
try
{
MailClient.Helpers.Client.getInstance().client.GetStream().EndWrite(res);
MailClient.Helpers.Client.getInstance().asyncRecieveEncryptedProtocolMessage(new AsyncCallback(LoginInfo_recieved));
}
catch { }
}
[STAThread]
private void LoginInfo_recieved(IAsyncResult res)
{
try
{
MailClient.Helpers.Client.getInstance().client.GetStream().EndRead(res);
MailClient.AsyncState state = (MailClient.AsyncState)res.AsyncState;
string answer = Aes.DecryptStringFromBytes_Aes(state.buffer, state.AES_KEY, state.AES_IV);
if (answer.Contains("OK"))
{
string[] answer_params = answer.Split(',');
LoggedUserInfo.USER_ID = Convert.ToInt32(answer_params[1]);
LoggedUserInfo.USER_LOGIN = answer_params[2];
//zalogowano
//this.TargetWindow = new MessageListsWindow();
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => this.TargetWindow = new MessageListsWindow()));
//System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => this.TargetWindow = new MessageListsWindow()));
}
else
{
//zle dane
System.Windows.MessageBox.Show("Zle dane");
}
}
catch(Exception exep) { }
}
This is declaration of asyncSendEncryptedProtocolMessage
asyncSendEncryptedProtocolMessage(string message, AsyncCallback callBack)
use function
clientStream.BeginWrite(encryptedMessage, 0, encryptedMessage.Length, callBack, st);
when code executes I get exception "The calling thread must be STA, because many UI components require this." I read about "SetApartmentState(ApartmentState.STA);" but I don't know how to apply it to callback. I've also tried with STAThread attribute but it doesn't work. I use MVVM Light framework.
StackTrace
" w System.Windows.Threading.DispatcherObject.VerifyAccess()\r\n w System.Windows.Application.get_MainWindow()\r\n w MailClient.ViewModel.MainWindowModel.LoginInfo_recieved(IAsyncResult res) w c:\\Users\\oem\\Documents\\Visual Studio 2012\\Projects\\MvvmLight3\\MailClient\\ViewModel\\MainWindowModel.cs:wiersz 171"

public static void Dispatch(this DispatcherObject source, Action func)
{
if (source.Dispatcher.CheckAccess())
func();
else
source.Dispatcher.Invoke(func);
}
And then use it like this:
MailClient.Helpers.Client.getInstance()
.asyncRecieveEncryptedProtocolMessage(new AsyncCallback(()=>
Application.Current.MainWindow.Dispatch(LoginInfo_recieved)));

Related

Wait for application launch without using Thread.Sleep() using FLAUI

I am new to using FLAUI and Automation Testing and would like to use it to test my system. At the moment I am using a Thread.Sleep() to wait till the application launches to then find the Login textbox. Is there a more efficient way to do this rather than using Thread.Sleep()?
At the moment i launch the application and use Thread.sleep(10000) to wait until the applicationis fully launched and that the logIn textbox is find-able before clicking on the control to input the password to enter the application. However I understand that Thread.Sleep is the worst way to tell the system to wait especially in automated tests. Could anyone offer any other things i could test out?
It is always the best to use Retry mechanism and wait until your main window loads and controls are visible. For example, after calling Application.Launch you can retry up to 30 seconds to find main window, and txtLogin in it:
Retry.WhileException(() =>
{
using (var automation = new UIA3Automation())
{
Window mainWindow = Application.GetMainWindow(automation, TimeSpan.FromSeconds(60));
Assert.IsNotNull(Mainwindow, "Main window is not found");
TextBox loginTextBox = mainWindow.FindFirstDescendant(x => x.ByAutomationId("txtLogin")).AsTextBox();
Assert.IsNotNull(loginTextBox, "txtLogin is not found");
}
}, TimeSpan.FromSeconds(30), null, true);
The question already has good answers, but I found another way to wait for any element (including main window) using the Retry class in FlaUI.Core.Tools.Retry class
[TestFixture]
public class SmokeTests
{
private Application _theApp;
private UIA3Automation _automation;
private Window _mainWindow;
private const int BigWaitTimeout = 3000;
private const int SmallWaitTimeout = 1000;
[SetUp]
public void Setup()
{
_theApp = FlaUI.Core.Application.Launch(new ProcessStartInfo("YOUR_APPLICATION.exe", "/quickStart"));
_automation = new UIA3Automation();
_mainWindow = _theApp.GetMainWindow(_automation);
}
[TearDown]
public void Teardown()
{
_automation?.Dispose();
_theApp?.Close();
}
[Test]
public void Foo()
{
// This will wait until the element is available, or timeout passed
var examplesWrapPanel = WaitForElement(() => _mainWindow.FindFirstDescendant(cf => cf.ByAutomationId("ExamplesWrapPanel")));
// This will wait for the child element or timeout
var exampleButton = WaitForElement(() => examplesWrapPanel?.FindFirstDescendant(cf => cf.ByAutomationId("Another Automation Id")).AsButton());
// Do something with your elements
exampleButton?.WaitUntilClickable();
exampleButton?.Invoke();
}
private T WaitForElement<T>(Func<T> getter)
{
var retry = Retry.WhileNull<T>(
() => getter(),
TimeSpan.FromMilliseconds(BigWaitTimeout));
if (!retry.Success)
{
Assert.Fail("Failed to get an element within a wait timeout");
}
return retry.Result;
}
}
}
private void RunProc()
{
Process.Start("exeName");
}
public async Task StartProcessAsync()
{
var result= await Task.Run(()=>RunProc());
//optional
Task.Delay(new TimeSpan.FromSeconds(5));
}
Did you try this solution?
public static void LaunchApplication(string exePath, string arguments, bool waitForExit, bool waitForStart, int waitForStartTimeout)
{
ProcessStartInfo thisProcessInfo = new ProcessStartInfo();
thisProcessInfo.CreateNoWindow = true;
thisProcessInfo.UseShellExecute = false;
thisProcessInfo.RedirectStandardOutput = false;
thisProcessInfo.FileName = exePath;
thisProcessInfo.Arguments = arguments;
using(Process thisProcess = Process.Start(thisProcessInfo))
{
if(waitForStart)
thisProcess.WaitForInputIdle(waitForStartTimeout);
if(waitForExit)
thisProcess.WaitForExit();
}
}

Handling the Windows.UI.Xaml.Application.Suspending event

I try to resolve the dreaded .WindowsPhone.exe!{<ID>}_Quiesce_Hang hang issue of my WinRT (Windows Phone 8.1) app.
At the moment I have the following handling of the Windows.UI.Xaml.Application.Suspending event:
private void App_Suspending(object iSender, SuspendingEventArgs iArgs)
{
SuspendingDeferral clsDeferral = null;
object objLock = new object();
try
{
clsDeferral = iArgs.SuspendingOperation.GetDeferral();
DateTimeOffset clsDeadline = iArgs.SuspendingOperation.Deadline;
//This task is to ensure that the clsDeferral.Complete()
//is called before the deadline.
System.Threading.Tasks.Task.Run(
async delegate
{
//Reducing the timeout by 1 second just in case.
TimeSpan clsTimeout = clsDeadline.Subtract(DateTime.UtcNow).Subtract(TimeSpan.FromSeconds(1));
if (clsTimeout.TotalMilliseconds > 100)
{
await System.Threading.Tasks.Task.Delay(clsTimeout);
}
DeferrerComplete(objLock, ref clsDeferral);
});
//Here I execute the suspending code i.e. I serializing the app
//state and save it in files. This may take more than clsTimeout
//on some devices.
...
//I do not call the Complete method here because the above
//suspending code is old-fashoin asynchronous i.e. not async but
//returns before the job is done.
//DeferrerComplete(objLock, ref clsDeferral);
}
catch
{
DeferrerComplete(objLock, ref clsDeferral);
}
}
private static void DeferrerComplete(object iLock, ref SuspendingDeferral ioDeferral)
{
lock (iLock)
{
if (ioDeferral != null)
{
try
{
ioDeferral.Complete();
}
catch
{
}
ioDeferral = null;
}
}
}
I have read the answer about the _Quiesce_Hang problem. I get the idea that it might be related to app storage activity. So my question is: what am I missing? Does my handling of the Suspending event look OK?

Gui beingInvoke issue with params

Below is a segment of code from a client handler class.
I know I am passing the wrong information as noted in the comment below. I just need to know exactly what I should pass to make it work.
public static void add2ClientList(string s)
{
MainWindow.mainWindow.ClientListBox.Items.Add(s);
}
Action<string> addToClientListBox = new Action<string> (add2ClientList);
public void addClientToPool(Client c)
{
if (ClientPool == null)
{
ClientPool = new Client[] { c };
uiDispatcher.BeginInvoke(addToClientListBox, DispatcherPriority.Background, CancellationToken.None, TimeSpan.Zero, c.getClientIp());
// above is the issue apparently I am passing the wrong params
return;
}
List<Client> temp = new List<Client>();
foreach (Client cc in ClientPool)
{
temp.Add(cc);
}
temp.Add(c);
ClientPool = temp.ToArray();
uiDispatcher.BeginInvoke(addToClientListBox, DispatcherPriority.Background, CancellationToken.None, TimeSpan.Zero, c.getClientIp());
}
The only thing that appears to be missing is your param to pass to the delegate, I assume you want the following:
uiDispatcher.CurrentDispatcher.BeginInvoke(addToClientListBox, new object[]{"ParamString"}, DispatcherPriority.Background);
If that's not exactly what you were asking let me know :)
Delegate d = (Action<string>)add2ClientList;
uiDispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, d, c.getClientIp());

Checking internet connectivity in Windows8 via C# fails

I'm trying to test the Internet connection in Windows8 from my C# application. I have a variable of type Boolean that returns me the connection status. When the boolean is true: do nothing. When the boolean becomes false, load my "NetworkDisconection" page. However, when I debug this line:
if (this.Frame != null)
I get an exception:
The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
Yeah, this method is on a different thread. How can I resolve this?
private bool bConection;
public HUB()
{
this.InitializeComponent();
bConection = NetworkInformation.GetInternetConnectionProfile()!= null;
NetworkInformation.NetworkStatusChanged += NetworkInformation_NetworkStatusChanged;
}
void NetworkInformation_NetworkStatusChanged(object sender)
{
if (NetworkInformation.GetInternetConnectionProfile() == null)
{
if (bConection == false)
{
bConection = true;
}
}
else
{
if (bConection == true)
{
bConection = false;
if (this.Frame != null)
{
Frame.Navigate(typeof(NetworkDisconection));
}
}
}
}
Use the following code and it should fix your problem...
Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
if (this.Frame != null)
{
Frame.Navigate(typeof(NetworkDisconection));
}
});
You should be able to acquire the Dispatcher directly since it looks like your code is in the code-behind of a XAML page (reference to this.Frame).
Tons of good info can be found in the C# Win8 Dev Forums. Search for Dispatcher and you will find several discussions on it. As always, check out GenApp for other great resources.
The NetworkInformation.NetworkStatusChanged event is raised on a non-UI thread. Similar to WinForms and WPF, you are still limited to accessing controls on the UI thread.
To get around this aspect, you'll have to invoke the UI thread similar to how you would on WinForms or WPF using this.Invoke/this.Dispatcher.Invoke.
At first you may try to use Window.Current.Dispatcher.RunAsync() but you will notice that Window.Current is always null here.
Instead, you should use CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync() in the Windows.ApplicationModel.Core namespace. Yeah, that's quite a mouthful for sure so I recommend this helper method in App.cs.
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
public static IAsyncAction ExecuteOnUIThread(DispatchedHandler action)
{
var priority = CoreDispatcherPriority.High;
var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
return dispatcher.RunAsync(priority, action);
}
I would also recommend this helper method too:
public static bool CheckInternetAccess()
{
var profile = NetworkInformation.GetInternetConnectionProfile();
if (profile == null) return false;
var connectivityLevel = profile.GetNetworkConnectivityLevel();
return connectivityLevel.HasFlag(NetworkConnectivityLevel.InternetAccess);
}
And finally:
async void NetworkInformation_NetworkStatusChanged(object sender)
{
var isConnected = CheckInternetAccess();
await ExecuteOnUIThread(() =>
{
if (!isConnected && this.Frame != null)
this.Frame.Navigate(typeof(ConnectionLostPage));
});
}

Lock around lambda event handler

I need to synchronize a sequence of operations that contains an asynchronous part.
The method looks into an image cache and returns the image if it's there (invokes a callback in reality). Otherwise it has to download it from the server. The download operation is asynchronous and fires an event on completion.
This is the (simplified) code.
private Dictionary<string, Bitmap> Cache;
public void GetImage(string fileName, Action<Bitmap> onGetImage)
{
if (Cache.ContainsKey(fileName))
{
onGetImage(Cache[fileName]);
}
else
{
var server = new Server();
server.ImageDownloaded += server_ImageDownloaded;
server.DownloadImageAsync(fileName, onGetImage); // last arg is just passed to the handler
}
}
private void server_ImageDownloaded(object sender, ImageDownloadedEventArgs e)
{
Cache.Add(e.Bitmap, e.Name);
var onGetImage = (Action<Bitmap>)e.UserState;
onGetImage(e.Bitmap);
}
The problem: if two threads call GetImage almost at the same time, they will both call the server and try to add the same image to the cache. What I should do is create lock at the beginning of GetImage and release it at the end of the server_ImageDownloaded handler.
Obviously this is not doable with the lock construct and it would not make sense, because it would be difficult to ensure that the lock is realeased in any case.
Now what I thought I could do is use a lambda instead of the event handler. This way I can put a lock around the whole section:
I have to lock the Cache dictionary at the beginning of the DownloadImage method and release it only at the end of the ImageDownloaded event handler.
private Dictionary<string, Bitmap> Cache;
public void GetImage(string fileName, Action<Bitmap> onGetImage)
{
lock(Cache)
{
if (Cache.ContainsKey(fileName))
{
onGetImage(Cache[fileName]);
}
else
{
var server = new Server();
server.ImageDownloaded += (s, e) =>
{
Cache.Add(e.Bitmap, e.Name);
onGetImage(e.Bitmap);
}
server.DownloadImageAsync(fileName, onGetImage); // last arg is just passed to the handler
}
}
}
Is this safe? Or the lock is immediately released after execution of GetImage, leaving the lambda expression unlocked?
Is there a better approach to solve this problem?
SOLUTION
In the end the solution was a bit of a mix of all the answers and comments, unfortunately I cannot mark-as-answer all of them. So here is my final code (removed some null checks/error cases/etc. for clarity).
private readonly object ImageCacheLock = new object();
private Dictionary<Guid, BitmapImage> ImageCache { get; set; }
private Dictionary<Guid, List<Action<BitmapImage>>> PendingHandlers { get; set; }
public void GetImage(Guid imageId, Action<BitmapImage> onDownloadCompleted)
{
lock (ImageCacheLock)
{
if (ImageCache.ContainsKey(imageId))
{
// The image is already cached, we can just grab it and invoke our callback.
var cachedImage = ImageCache[imageId];
onDownloadCompleted(cachedImage);
}
else if (PendingHandlers.ContainsKey(imageId))
{
// Someone already started a download for this image: we just add our callback to the queue.
PendingHandlers[imageId].Add(onDownloadCompleted);
}
else
{
// The image is not cached and nobody is downloading it: we add our callback and start the download.
PendingHandlers.Add(imageId, new List<Action<BitmapImage>>() { onDownloadCompleted });
var server = new Server();
server.DownloadImageCompleted += DownloadCompleted;
server.DownloadImageAsync(imageId);
}
}
}
private void DownloadCompleted(object sender, ImageDownloadCompletedEventArgs e)
{
List<Action<BitmapImage>> handlersToExecute = null;
BitmapImage downloadedImage = null;
lock (ImageCacheLock)
{
if (e.Error != null)
{
// ...
}
else
{
// ...
ImageCache.Add(e.imageId, e.bitmap);
downloadedImage = e.bitmap;
}
// Gets a reference to the callbacks that are waiting for this image and removes them from the waiting queue.
handlersToExecute = PendingHandlers[imageId];
PendingHandlers.Remove(imageId);
}
// If the download was successful, executes all the callbacks that were waiting for this image.
if (downloadedImage != null)
{
foreach (var handler in handlersToExecute)
handler(downloadedImage);
}
}
The lambda expression is converted into a delegate within a lock, but the body of the lambda expression will not automatically acquire the lock for the Cache monitor when the delegate is executed. So you may want:
server.ImageDownloaded += (s, e) =>
{
lock (Cache)
{
Cache.Add(e.Bitmap, e.Name);
}
onGetImage(e.Bitmap);
}
You have another potential problem here. This code:
if (Cache.ContainsKey(fileName))
{
onGetImage(Cache[fileName]);
}
If some other thread removes the image from the cache after your call to ContainsKey but before the next line is executed, it's going to crash.
If you're using Dictionary in a multi-threaded context where concurrent threads can be reading and writing, then you need to protect every access with a lock of some kind. lock is convenient, but ReaderWriterLockSlim will provide better performance.
I would also suggest that you re-code the above to be:
Bitmap bmp;
if (Cache.TryGetValue(fileName, out bmp))
{
onGetImage(fileName);
}
If you're running .NET 4.0, then I would strongly suggest that you look into using ConcurrentDictionary.
Why don't you just keep a a collection of image filenames that are being downloaded, and have the code for a thread be:
public void GetImage(string fileName, Action<Bitmap> onGetImage)
{
lock(Cache)
{
if (Cache.ContainsKey(fileName))
{
onGetImage(Cache[fileName]);
}
else if (downloadingCollection.contains(fileName))
{
while (!Cache.ContainsKey(fileName))
{
System.Threading.Monitor.Wait(Cache)
}
onGetImage(Cache[fileName]);
}
else
{
var server = new Server();
downloadCollection.Add(filename);
server.ImageDownloaded += (s, e) =>
{
lock (Cache)
{
downloadCollection.Remove(filename);
Cache.Add(e.Bitmap, e.Name);
System.Threading.Monitor.PulseAll(Cache);
}
onGetImage(e.Bitmap);
}
server.DownloadImageAsync(fileName, onGetImage); // last arg is just passed to the handler
}
}
}
That is more or less the standard monitor pattern, or would be if you refactored the lambda expression into a member function like GetImage. You should really do that. It will make the monitor logic easier to reason about.

Categories