开发者

How do I update a WPF Window with information from a background thread?

开发者 https://www.devze.com 2023-02-07 14:09 出处:网络
I\'m creating a wpf application which performs many tasks in the backgound, but still requires the UI to be responsive and to display the status of the various background tasks.It also has the option

I'm creating a wpf application which performs many tasks in the backgound, but still requires the UI to be responsive and to display the status of the various background tasks. It also has the option to not display the UI at all, in which case the status messages should be discarded without creating an instance of the main form at all.

What I've attempted is to remove

StartupUri="MainWindow.xaml"

from App.xaml. Then, in App.xaml.cs, I have

`

    public App()
    {
        Startup += new StartupEventHandler(App_Startup);
    }

    void App_Startup(object sender, StartupEventArgs e)
    {
        // Code which loads application settings is here

        if (pf.ShowUI)
        {
            MainWindow mainWindow = new MainWindow();
            mainWindow.Show();
        }

        // The background processes will begin here.

    }`

This shows the main form, if necessary, and starts all the background processes. This part works.

In order to send messages from the background to the UI, I've implemented a very basic messenger:

`

internal interface IMessageHandler
{
    void ReceiveMessage(string message);
}

internal class Messenger
{
    private static List<IMessageHandler> _handlers;

    internal static void AddHandler(IMessageHandler handler)
    {
        _handlers.Add(handler);
    }

    internal static void RemoveHandler(IMessageHandler handler)
    {
        try
        {
            _handlers.Remove(handler);
        }
        catch (Exception e开发者_运维百科x) {}
    }

    internal static void Broadcast (string message)
    {
        foreach (IMessageHandler handler in _handlers)
        {
            handler.ReceiveMessage(message);
        }
    }
}`

The main form implements the IMessageHandler interface, and adds itself to the Messenger as a handler when it starts up. Any process that needs to send a status to the main form just needs to call the Broadcast method of the messenger.

The problem I'm having, is that the messages are not being shown on the form until the background processes complete, and the UI is locked up until then as well.

The code in the UI which handles receiving messages is as follows:

`

    public void ReceiveMessage(string message)
    {
        Dispatcher.Invoke(DispatcherPriority.Normal,
                new Action<string>(AddText),
                message);
    }

    private void AddText(string text)
    {

        Label myLabel = new Label();
        myLabel.Content = text;
        stackPanel1.Children.Add(myLabel);
        if (stackPanel1.Children.Count > 5)
        {
            stackPanel1.Children.RemoveAt(0);
        }
    }`

Why are my background processes freezing my UI? What can I do to prevent it? And why is my UI not updating with the status messages?


Maybe this is your problem:

   Dispatcher.Invoke(DispatcherPriority.Normal,
                new Action<string>(AddText),
                message);

Try change this to,

   Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                new Action<string>(AddText),
                message);

Because when you use Invoke, the method gets executed and the application waits for it to complete, but with BeginInvoke the method is invoked Asychnronously and the application continues to execute while the method referenced in BeginInvoke is executed.

Read this: whether to use Invoke or BeginInvoke


Use the below code to avoid freezing the UI. In my application I have used a BackgroundWorker class. By changing anything on the form using code, a run time error is thrown.

I am using the below code to avoid this and it works perfectly for me.

Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
{
   rtf_status.AppendText("Validating XML against schema...Please wait\n");
}));

Note the part after the between braces ('{}') this is where you should place your code if you wish to change something on the form.

0

精彩评论

暂无评论...
验证码 换一张
取 消