简体   繁体   中英

How do you create a SolidColorBrush in UWP from a color in a C# Class Library?

I have a UWP app that has XAML pages and class libraries to help aggregate certain functions.

I have certain objects (dynamic) that have a property called Brush. This property holds any Brush that can be bind in XAML to indicate the brush used to draw a control/item within a control with this brush. This is all wrapped in various converters to used during Binding.

I am running into several issues:

  1. Running the converter from a non-UI dispatcher throws the "Marshalled For Another Thread" error.

  2. Wrapping the new SolidColorBrush(color) within a Dispatcher.RunAsync method, causes a deadlock.

I create a new function that is async to make it more convenient to run it within a sync method.

Here is the code for the converter (called RandomBrush):

return Task.Run(async () => await Data.CreateSolidColorBrush(color)).Result;

Here is the code for Data.CreateSolidColorBrush function:

public async static Task<Brush> CreateSolidColorBrush(Color color)
        {
            Brush brush = null;
            var dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
            //var dispatcher = Window.Current.Dispatcher;
            await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => 
            {
                try { brush = new SolidColorBrush(color); } 
                catch (Exception ex) 
                { }
            });
            return brush;
        }

I have tried various methods of async/task/action/etc but some don't run the action at all and some cause a deadlock.

What is the best way to create a brush from a color without all the complications!

First:

return Task.Run(async () => await Data.CreateSolidColorBrush(color)).Result;

Can be simplified to:

return Data.CreateSolidColorBrush(color).Result;

About the dead lock:

Dispatcher.RunAsync put the lambda on the list of pending work in the dispatcher and it return a Task that will finish when the work is done.

You await the task so you will wait for its completion. But you are probably on the thread of the dispatcher and it wait for you to continue the execution of pending works. This is a dead lock.

You should check if you are not on the UI thread before calling RunAsync , execute immediately if you are on the UI thread.

Finally I'm not even sure you need too be on the UI thread to build a brush. So test that when you will have a working code.

About the Marshalled For Another Thread :

You didn't show any code. If what's above does not fix it, use the dispatcher to set view properties with RunAsync . Again you will have to test if you are on the UI thread or not.

See https://stackoverflow.com/a/63376211/361177 for an helper that do the test and execute an action immediately if you are on the UI thread or via the dispatcher otherwise.

I was able to fix it with the following code:

public async static Task CreateSolidColorBrush(Color color)

{
    Brush brush = null;
    Threading.ThreadSafe(() => brush = new SolidColorBrush(color));
    if (brush == null)
    {
        Threading.ThreadSafe(() =>
        {
            try { brush = new SolidColorBrush(color); }
            catch (Exception Ex)
            { }
        }
        );
    }
    return brush;
}

public static class Threading
    {

        private static CoreDispatcher Dispatcher =>
        Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;

        public static async void ThreadSafe(DispatchedHandler action)
        {
            // Calls Dispatcher.RunAsync to run a method on the Main UI Thread
            IAsyncAction UiThread(DispatchedHandler proc) => Dispatcher.RunAsync(CoreDispatcherPriority.Normal, proc);

            // Checks to see if this was called from the Main UI thread 
            // If we are in the Main UI thread then Invoke the action 
            // Otherwise: Send it to run in the Main Ui Thread.

            if (Dispatcher.HasThreadAccess) 
            {
                action.Invoke(); 
            } 
            else 
            {
                await UiThread(action); 
            }
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM