Setting Culture in .net5 WPF application - wpf

In a WPF application I try to set the culture in OnStartup.
protected override async void OnStartup(StartupEventArgs startupEventArgs)
{
base.OnStartup(startupEventArgs);
var a = new CultureInfo(ConfigurationManager.AppSettings["Language"]);
Thread.CurrentThread.CurrentCulture = a;
Thread.CurrentThread.CurrentUICulture = a;
CultureInfo.DefaultThreadCurrentCulture = a
CultureInfo.DefaultThreadCurrentUICulture = a;
CultureInfo.CurrentCulture = a;
}
If I start a method from the MainWindow with Click event or with ICommand then in the method the Thread.CurrentThread.CurrentUICulture will be always en-US, which is very strange (can sombody exaplain?). I can set again to the desired Culture but I have to do it in each called method one by one. Is there an alternative?
In .net4.7 there was a workaround but it does not work in .net5.

The reason for this behavior is how async methods are implemented. async methods have their own special execution context. This context has it's own CultureInfo, which is inherited from the non-async context that invokes the async method.
In your case, the async context's culture is inherited from the main thread, before the culture is changed.
What you can do is to implement the already suggested solution using the Dispatcher.InvokeAsync to postpone the CultureInfo configuration. This way the configuration is executed outside the async context:
Dispatcher.InvokeAsync(() => CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-EN"));
Since this can mess up your initialization routine, as the real context would be avaailable after the application is configured and the main Window displayed, you would prefer a different solution.
You can for example used an event based initialization routine, where you run low-level application configuration like culture configuration first and continue with the remaining initialization that involves asynchronous operations in an async context:
App.xaml.cs
// Event may be defined on a different class
private event EventHandler ConfigurationCompleted;
private void OnConfigurationCompleted() => this.ConfigurationCompleted?.Invoke(this, EventArgs.Empty);
protected override void OnStartup(StartupEventArgs startupEventArgs)
{
this.ConfigurationCompleted += ConfigureInAsyncContext;
// Do "low-level" application configuration. Code may be executed in a different class context
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-EN");
...
// Continue in async context
OnConfigurationCompleted();
}
private async void ConfigureInAsyncContext(object sender, EventArgs e)
{
// TODO::Execute async operations
new MainWindow().Show();
}
The key is to separate the non-async configuration from the async initialization.

Related

WPF NotifyIcon From Background Thread

I know normally one is not supposed to touch UI elements from threads other than the UI thread, but I am new to WPF and I am wondering if my current working implementation can be improved.
I have an application that is comprised solely of a notification tray icon, and I want to update that icon from a background thread.
Here is my Program.cs entry point:
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
using (IconHandler notify = new IconHandler())
{
notify.Display();
Application.Run();
}
}
}
This is my IconHandler.cs notification icon handler class:
class IconHandler : IDisposable
{
NotifyIcon ni;
public IconHandler()
{
ni = new NotifyIcon();
}
public void Display()
{
ni.MouseClick += new MouseEventHandler(ni_MouseClick);
ni.Icon = Resources.icon1;
ni.Visible = true;
new Thread(new ThreadStart(UpdateIcon)).Start();
}
public void UpdateIcon()
{
while (true)
{
// reference ni directly, it updates fine
}
}
public void Dispose()
{
ni.Dispose();
}
void ni_MouseClick(object sender, MouseEventArgs e)
{
// something useful
}
}
Is there anything blatantly incorrect about this? It seems a bit fishy to me - it was just my first attempt. It seems to work for what I want to do, does anyone have any suggestions for a better implementation? Will I run into lifecycle issues with this setup?
Is there anything blatantly incorrect about this? It seems a bit fishy to me - it was just my first attempt. It seems to work for what I want to do, does anyone have any suggestions for a better implementation? Will I run into lifecycle issues with this setup?
To begin with NotifyIcon is not a WPF control, but comes from the Windows Forms namespace. As such it has normal C# properties (e.g. Icon, Visible) meaning you have been able to alter the icon property in the non-UI thread without an exception being raised. If you had used a WPF controls then they have Dependency Properties and direct manipulation of Dependency Properties outside of the UI thread will cause an exception to be raised.
Will I run into lifecycle issues with this setup?
You've currently NOT created a WPF window or WPF controls. If your application develops such that you start using WPF and the UpdateIcon method is expanded to do more than you currently do and access these WPF objects then yes you will need a strategy to deal with the updates from non-UI threads.
You can hide some of this cross-threaded access using some helper methods.
Example 1 If your strategy becomes referencing WPF controls programmatically from the background thread then you can use a helper method such as this.
It first checks if the call is on the UI thread, if so then it updates the control directly, otherwise it will schedule that the method (itself) be called from the UI thread at a later point in time.
I've used BeginInvoke here so that the background thread can continue before the UI thread has actually called the method. If you want to block the background thread then use Invoke instead.
public void UpdateLabel(Label control, string text)
{
if (Application.Current.Dispatcher.CheckAccess())
control.Content = text;
else
Application.Current.Dispatcher.BeginInvoke(new System.Action(() => UpdateLabel(control, text)), DispatcherPriority.Normal);
}
Example 2
If your strategy uses Events raised on the background thread to update the WPF controls programmatically then you can hide some of the cross-threading calls as part of raising the event, leaving the WPF update routine quite clean and simple to read.
Any event handlers of this event can be coded knowing that the call will be made from the UI thread, so no threading issues.
public void OnRaiseEvent(EventHandler handler, EventArgs args)
{
if (handler != null)
{
if (Application.Current.Dispatcher.CheckAccess())
handler(sender, new PropertyChangedEventArgs(propName));
else
Application.Current.Dispatcher.BeginInvoke(new System.Action(() => handler(sender, args)), DispatcherPriority.Normal);
}
}
Example 3
If your future strategy fully utilizes the benefits of WPF with Binding (as opposed to programmatically updating your WPF controls), then you can embed the cross-threading code into the data-bound objects.
If for example your XAML databinds to the MyProperty property of an instance of the MyDataClass class and that class implements the INotifyPropertyChanged interface you can put the cross-threading code in the data class making it possible to update the data from any thread. Here is the example of the class:-
public class MyDataClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _myProperty;
public string MyProperty { get { return _myProperty;} set { PropertyChanged.SetValueAndNotify(this, ref _myProperty, value); } }
}
This class utilizes the SetValueAndNotify extension method on the PropertyChanged event. It is in here we hide the cross-threading code to simplify other parts of the code. Here's the definition of this extension method.
public static class PropertyChangedExtension
{
public static void SetValueAndNotify<T>(this PropertyChangedEventHandler handler, object sender, ref T destination, T source, [CallerMemberName] string propName = "notset")
{
// Is the new value different from the previous value? If there is no difference then there is nothing more to do
if (Equals(destination, source))
return;
// If we got to this point then the new value is different from the old value, so lets make the assignemnt and raise the property changed event
destination = source;
if (handler != null)
{
if (Application.Current.Dispatcher.CheckAccess())
handler(sender, new PropertyChangedEventArgs(propName));
else
Application.Current.Dispatcher.BeginInvoke(new System.Action(() => handler(sender, new PropertyChangedEventArgs(propName))), DispatcherPriority.Normal);
}
}
}
The above example uses the [CallerMemberName] attribute from C#5 to remove any typing errors in supplying the property name for the INotifyPropertyChanged arguments. If you are not using the latest then you will need to modify the getter and setter as follows:-
public string MyProperty { get { return _myProperty;} set { PropertyChanged.SetValueAndNotify(this, ref _myProperty, value, "MyProperty"); } }
You must always update UI from UI thread only, however, you can schedule some work on UI thread from background thread using dispatcher
public void Display()
{
ni.MouseClick += new MouseEventHandler(ni_MouseClick);
ni.Icon = Resources.icon1;
ni.Visible = true;
new Thread(new ThreadStart(UpdateIcon)).Start();
}
public void UpdateIcon()
{
while (true)
{
//do some long running work
Application.Current.Dispatcher.Invoke(()=>{
//update ui
});
}
}
But if you don't have long running work and you just want to do something periodically, you should use DispatcherTimer instead of loop in background thread.
The while(true) loop in your code will cause heavy CPU/resource usage. maybe add e.g. Thread.Sleep(1000) into the loop to allow for a break between updates.
The best usage of background threads is to perform the long-running work (e.g. communication with server/DB) on the background thread and once the thread completes, have the UI thread update the UI.
With BackgroundWorker:
var worker = new BackgroundWorker();
worker.DoWork += (sender, args) =>
{
// long running work
};
worker.RunWorkerCompleted += (sender, args) =>
{
// Update UI
};
worker.RunWorkerAsync();
async/await pattern:
public async void DoWork()
{
// Do long running task
var data = await Task.Run(() => new object());
// Update UI here
}
TaskFactory:
Task.Factory.StartNew(() => new Object()).ContinueWith(task => MessageBox.Show(task.Result.ToString()), TaskScheduler.FromCurrentSynchronizationContext());
If the UI needs to update on a constant loop, maybe use a timer to restart the process on a regular basis. This will save your CPU from taking a pounding.

Canvas InvalidateVisual() thread exception

I'm developing an app that shows some images (with some filter effects) using Canvas.
I've a static class called RendererBooster. This class' RenderImage() method renders the image with given effects WITH TASK on background and sets the MyViewer coltrol's _bSource property with the rendered image. (MyViewer is derived from Canvas)
On the other hand, I've a DispatcherTimer inside the MyViewer class. This DispatcherTimes ticks every 2ms and checks if _bSource is NOT NULL, calls the Canvas' InvalidateVisual() method.
Everything is fine untill here.
My overridden OnRender() method just draws that _bSource to screen and sets _bSource to NULL. After that, I get Cannot use a DependencyObject that belongs to a different thread than its parent Freezable exception. Here is some sample code. What can I do to fix it?
RendererBooster
public static class RendererBooster
{
public static void RenderImage()
{
MyViewer viewer = ViewerManager.GetViewer();
Task.Factory.StartNew(() =>
{
unsafe
{
// render
// render again
// render again ..
// ...
// when rendering is done, set the _bSource.
viewer._bSource = BitmapSource.Create(sizeDr.Width, sizeDr.Height, 96, 96, PixelFormats.Prgba64, null, mlh.Buffer, sStride * sizeDr.Height, sStride);
}
});
}
}
MyViewer
public class MyViewer : Canvas
{
public BitmapSource _bSource = null;
private object _lockObj = new object();
public MyViewer()
{
DispatcherTimer dt = new DispatcherTimer();
dt.Interval = TimeSpan.FromMilliseconds(2);
dt.Tick += dt_Tick;
dt.Start();
}
void dt_Tick(object sender, EventArgs e)
{
if (_bSource == null)
return;
InvalidateVisual();
}
protected override void OnRender(DrawingContext dc)
{
lock (_lockObj)
{
dc.DrawImage(_bSource, new System.Windows.Rect(new System.Windows.Point(0, 0), new System.Windows.Size(ActualWidth, ActualHeight)));
_bSource = null;
// this is the line that i get the exception
//Cannot use a DependencyObject that belongs to a different thread than its parent Freezable
}
}
}
NOTE: Why I'm doing the rendering work on an other function / class? Because rendering takes 3-4 seconds. If I render inside the OnRender() method, UIThread freezes the application.
The BitmapSource class inherits Freezable, which in turn inherits DependencyObject. As you know, DependencyObjects have thread affinity (because they inherit DispatcherObject). That is, every DependencyObject first checks whether you are allowed to access it from current thread using the CheckAccess() and VerifyAccess() methods.
In your example, you create a BitmapSource in the worker thread (using a Task), but try to use it in the other: the OnRender() method will be called on the UI thread.
So, one solution could be to create your BitmapSource in the UI thread. You could use e.g. Dispatcher.Invoke() or SynchronizationContext.Post() methods for this. If you're using .NET 4.5+, I would suggest you to change your Task code to something like:
public static async Task RenderImage()
{
MyViewer viewer = ViewerManager.GetViewer();
await Task.Run(() =>
{
// your rendering code
})
.ContinueWith(t =>
{
// BitmapSource creating code
},
TaskScheduler.FromCurrentSynchronizationContext());
}
With this approach, your time consuming rendering will be processed on a worker thread, but the BitmapSource object creation will occur on the calling UI thread. You have to ensure the thread safety for your unsafe objects, however.
Furthermore, I would suggest you to make the _bSource field private. Wrap the access to it in a property with a lock statement. With your current implementation, the multithreading synchronization will not work properly (you assign the value without using a lock).
// don't have to initialize it with null, because all .NET reference objects
// will be initialized with their default value 'null' automatically
private BitmapSource _bSource;
public BitmapSource BSource
{
get { lock (_lockObj) { return this._bSource; } }
set { lock (_lockObj) { this._bSource = value; } }
}
You have to use this property everywhere, including your MyViewer class methods. Doing so, you will be safe in accessing the object in a multithreading environment:
void dt_Tick(object sender, EventArgs e)
{
if (this.BSource == null)
return;
// ...
}
If it's too complicated for you, I've a simpler solution too.
There is one thing about Freezables to mention:
Thread safety: a frozen Freezable object can be shared across threads.
So, you just could freeze your BitmapSource object after creation to allow a cross-thread access to it:
BitmapSource source = BitmapSource.Create(/* arguments... */);
source.Freeze();
viewer.BSource = source;

Will caliburn.micro do the right thing with async method on ViewModel?

As mentioned elsewhere, the new .NET async/await model propagates through layers of software like a virus. A recent async change has now bubbled up to my view model, and I am wondering if it is safe change declaration from public void DoStuff() to public async Task DoStuff() ?
Thanks!
The support of asynchronous programming model in Caliburn.Micro is pretty good now.
Few things you can do:
Use async/await in Action method. Be careful, as action methods are technically event handlers, you shoud do async void rather than async Task.
Asynchronous event handlers for Screen's events, like Activated, ViewLoaded and other.
Asynchronous overrides for Screen's methods: OnInitialize, OnActivate, ... You can override then as protected override async void OnInitialize(){} and inside you can await another task.
Convert Coroutines to Tasks. Use ExecuteAsync() extension method. Coroutines still have some advantages in some scenarios, like execution context.
IHandleWithTask<TMessage> - pretty handy...
There's a blog post desribing some use cases with few code snippets. And a GitHub repository with sample project I've used to play with async/await in Caliburn.
The answer is 'yes', starting with Caliburn.Micro 1.5.
See release announcement.
It's safe, but will break your existing global exception handling. After I did the refactoring, I didn't see any error dialogues anymore, to fix that, I had to subscribe to the Coroutine.Completed event:
Coroutine.Completed += (s, a) =>
{
//Do something here ...
};
You can do that in your App.xaml.cs file.
Example from my code on how I handle all possible errors raised in my app:
protected override void OnStartup(StartupEventArgs e)
{
SetupExceptionHandlers();
base.OnStartup(e);
}
private void SetupExceptionHandlers()
{
AppDomain.CurrentDomain.UnhandledException += (s, a) =>
{
HandleException((Exception)a.ExceptionObject, "AppDomain.CurrentDomain.UnhandledException");
};
Current.DispatcherUnhandledException += (s, a) =>
{
HandleException(a.Exception, "Application.Current.DispatcherUnhandledException");
a.Handled = true;
};
TaskScheduler.UnobservedTaskException += (s, a) =>
{
Dispatcher.InvokeAsync(() => HandleException(a.Exception, "TaskScheduler.UnobservedTaskException"));
a.SetObserved();
};
Coroutine.Completed += (s, a) =>
{
if (a.Error != null)
{
HandleException(a.Error, "Coroutine.Completed");
}
};
}
private void HandleException(Exception exception, string source)
{
logger.Error(exception, "Unhandled exception occured (Source: {0})", source);
var msg = new ShowErrorDialogEvent(exception, exception.GetBaseException().Message);
eventAggregator.PublishOnUIThread(msg);
}
In-case you're wondering, the logger and eventAggregator variables are instantiated from the bootstrapper class in the OnStartup method before calling DisplayRootViewFor.
Marco Amendola, a project manager in the Caliburn.Micro project wrote an article that has this title: Coroutines are dead. Long live Coroutines. and he titled it this way because of the emergence of the async/wait programming model and if you read the article you will see that async/wait bring to life what Coroutines did in the past so i assume you could use them safely where you have used Coroutines before. i advise you to read the article.

Can I set the culture of a silverlight application from a page class?

In my SL application, I have a page that connects to a web service to retrieve some culture information such as date formats. As this information is not known at the instantiation of the silverlight application, I cannot set this in the public App() constructor. The following lines don't seem to work in the async completed method of the service call within the page class:
var dateFormatString = e.Result.DateFormatString;
Thread.CurrentThread.CurrentCulture = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern = dateFormatString;
Is there a way to set the culture of the silverlight application from a page class?
Set it in the main thread (your asyncCompleted is probably running on a different thread).
Let me know if you do not know how to do this.
There is no need to clone the Culture. (line 2 in your code).
Just set it directly:
var dateFormatString = e.Result.DateFormatString;
Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern = dateFormatString;
** EDIT added sample code to call from UI Thread.
You can always pass state to an async wcf call. In this case I am passing a Dispatcher.
Once the callback is called use the Dispatcher to change the UI Culture in the UI thread.
I wrote this off the top of my head, but should be sufficient to give you an idea of what you need to do.
public void SetCulture()
{
YourWcfProxy.GetCultureInfoCompleted += GetCultureInfoCompleted;
object state = Dispatcher; // variable just for clarity.
YourWcfProxy.GetCultureInfoAsync(state);
}
private void GetCultureInfoCompleted(object sender, GetCultureInfoCompletedCompletedEventArgs e)
{
Dispatcher dispatcher = e.UserState as Dispatcher;
dispatcher.BeginInvoke(() =>
{
// set the ui culture here!
}
);
}
** EDIT 2 (answer question)
If you have a UIElement handy, you can use it's Disptacher property.
Otherwise use the static:
Deployment.Current.Dispatcher

Run code on UI thread without control object present

I currently trying to write a component where some parts of it should run on the UI thread (explanation would be to long).
So the easiest way would be to pass a control to it, and use InvokeRequired/Invoke on it.
But I don't think that it is a good design to pass a control reference to a "data/background"-component, so I'm searching for a way to run code on the UI thread without the need of having a control available.
Something like Application.Dispatcher.Invoke in WPF...
any ideas,
thx
Martin
There's a better, more abstract way to do this that works on both WinForms and WPF:
System.Threading.SynchronizationContext.Current.Post(theMethod, state);
This works because WindowsForms installs a WindowsFormsSynchronizationContext object as the current sync context. WPF does something similar, installing it's own specialized synchronization context (DispatcherSynchronizationContext).
.Post corresponds to control.BeginInvoke, and .Send corresponds to control.Invoke.
First, in your form constructor, keep a class-scoped reference to the SynchronizationContext.Current object (which is in fact a WindowsFormsSynchronizationContext).
public partial class MyForm : Form {
private SynchronizationContext syncContext;
public MyForm() {
this.syncContext = SynchronizationContext.Current;
}
}
Then, anywhere within your class, use this context to send messages to the UI:
public partial class MyForm : Form {
public void DoStuff() {
ThreadPool.QueueUserWorkItem(_ => {
// worker thread starts
// invoke UI from here
this.syncContext.Send(() =>
this.myButton.Text = "Updated from worker thread");
// continue background work
this.syncContext.Send(() => {
this.myText1.Text = "Updated from worker thread";
this.myText2.Text = "Updated from worker thread";
});
// continue background work
});
}
}
You will need the following extension methods to work with lambda expressions: http://codepaste.net/zje4k6
You are right, it is not good to pass controls to threads. Winforms controls are single-threaded, passing them to multiple threads can cause race conditions or break your UI. Instead, you should make your thread's features available to the UI and let it call the thread when the UI is good and ready. If you want to have background threads trigger UI changes, expose a background event and subscribe to it from the UI. The thread can fire off events whenever it wants and the UI can respond to them when it is able to.
Creating this bidirectional communication between threads that does not block the UI thread is a lot of work. Here is a highly abbreviated example using a BackgroundWorker class:
public class MyBackgroundThread : BackgroundWorker
{
public event EventHandler<ClassToPassToUI> IWantTheUIToDoSomething;
public MyStatus TheUIWantsToKnowThis { get { whatever... } }
public void TheUIWantsMeToDoSomething()
{
// Do something...
}
protected override void OnDoWork(DoWorkEventArgs e)
{
// This is called when the thread is started
while (!CancellationPending)
{
// The UI will set IWantTheUIToDoSomething when it is ready to do things.
if ((IWantTheUIToDoSomething != null) && IHaveUIData())
IWantTheUIToDoSomething( this, new ClassToPassToUI(uiData) );
}
}
}
public partial class MyUIClass : Form
{
MyBackgroundThread backgroundThread;
delegate void ChangeUICallback(object sender, ClassToPassToUI uiData);
...
public MyUIClass
{
backgroundThread = new MyBackgroundThread();
// Do this when you're ready for requests from background threads:
backgroundThread.IWantTheUIToDoSomething += new EventHandler<ClassToPassToUI>(SomeoneWantsToChangeTheUI);
// This will run MyBackgroundThread.OnDoWork in a background thread:
backgroundThread.RunWorkerAsync();
}
private void UserClickedAButtonOrSomething(object sender, EventArgs e)
{
// Really this should be done in the background thread,
// it is here as an example of calling a background task from the UI.
if (backgroundThread.TheUIWantsToKnowThis == MyStatus.ThreadIsInAStateToHandleUserRequests)
backgroundThread.TheUIWantsMeToDoSomething();
// The UI can change the UI as well, this will not need marshalling.
SomeoneWantsToChangeTheUI( this, new ClassToPassToUI(localData) );
}
void SomeoneWantsToChangeTheUI(object sender, ClassToPassToUI uiData)
{
if (InvokeRequired)
{
// A background thread wants to change the UI.
if (iAmInAStateWhereTheUICanBeChanged)
{
var callback = new ChangeUICallback(SomeoneWantsToChangeTheUI);
Invoke(callback, new object[] { sender, uiData });
}
}
else
{
// This is on the UI thread, either because it was called from the UI or was marshalled.
ChangeTheUI(uiData)
}
}
}
Put the UI manipulation in a method on the form to be manipulated and pass a delegate to the code that runs on the background thread, à la APM. You don't have to use params object p, you can strongly type it to suit your own purposes. This is just a simple generic sample.
delegate UiSafeCall(delegate d, params object p);
void SomeUiSafeCall(delegate d, params object p)
{
if (InvokeRequired)
BeginInvoke(d,p);
else
{
//do stuff to UI
}
}
This approach is predicated on the fact that a delegate refers to a method on a particular instance; by making the implementation a method of the form, you bring the form into scope as this. The following is semantically identical.
delegate UiSafeCall(delegate d, params object p);
void SomeUiSafeCall(delegate d, params object p)
{
if (this.InvokeRequired)
this.BeginInvoke(d,p);
else
{
//do stuff to UI
}
}
What about passing a System.ComponentModel.ISynchronizeInvoke? That way you can avoid passing a Control.

Resources