Showing busy indicator control inside a UI

无人久伴 提交于 2019-12-25 01:41:36

问题


I have modified code, but now I have another problem. The InvalidOperation exception occurs inside if statement on validating user info. It says that the calling thread cannot access this object because a different thread owns it.Any sugestions?

 private void finishConfigButton_Click(object sender, RoutedEventArgs e)
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.WorkerSupportsCancellation = true;
        bool validated = false;

        errorLabel.Visibility = System.Windows.Visibility.Collapsed;
        validationProfile.IsBusy = true;
        finishConfigButton.IsEnabled = false;
        backToLoginHyperlink.IsEnabled = false;

        worker.DoWork += (o, ea) =>
        {
            if (newUser.ValidateNewUserInformation(newNameTextBox.Text, newEmailTextBox.Text, newUsernameTextBox.Text, newPasswordPasswordBox.Password, ref errorLabel))
            {
                validated = true;

                string activeDir = Environment.SystemDirectory.Substring(0, 1) + @":\Users\" + Environment.UserName + @"\My Documents\SSK\Users";
                string newPath = System.IO.Path.Combine(activeDir, newUser.Username);
                Directory.CreateDirectory(newPath);

                newUser.SaveUserData(newUser);

                newPath = System.IO.Path.Combine(activeDir, newUser.Username + @"\Settings");
                Directory.CreateDirectory(newPath);

                newUserSettings.SetDefaultValues();
                newUserSettings.SaveSettings(newUser, newUserSettings);
            }
            else
                validated = false;

            if (worker.CancellationPending)
            {
                ea.Cancel = true;
                return;
            }
        };

        worker.RunWorkerCompleted += (o, ea) =>
        {
            validationProfile.IsBusy = false;
            finishConfigButton.IsEnabled = true;
            backToLoginHyperlink.IsEnabled = true;
        };

        worker.RunWorkerAsync(this);

        if (validated)
        {
            IntelliMonitorWindow intelliMonitor = new IntelliMonitorWindow(newUser, newUserSettings);
            intelliMonitor.Show();
            this.Close();
        }
        else
            errorLabel.Visibility = System.Windows.Visibility.Visible;
    }

回答1:


What you are doing here is running everything on the UI thread. This means that while the heavy code is running, you are blocking the UI from repainting, and hence the validationProfile is not updated untill the end of the method, where IsBusy is set to false.

What you need to do is to process the heavy code into a new thread, which can update the UI at the same time.

Take a look at this blog post written by Brian Lagunas, the creator of Extended Toolkit: http://elegantcode.com/2011/10/07/extended-wpf-toolkitusing-the-busyindicator/

He explains how to use the BusyIndicator with a BackgroundWorker.




回答2:


The busy indicator in your XAML code does not have any content. Put some control(s) into it:

<wpfet:BusyIndicator Name="validationProfile" IsBusy="False" BusyContent="Working...Please wait"  DisplayAfter="0" Background="DimGray">
    <Grid>
        ...
    </Grid>
</wpfet:BusyIndicator>

If you change to busy, those controls will get disabled and the BusyIndicator will appear above them.

I suppose you want to wrap the whole <Grid Background="LightGray"> with the BusyIndicator.




回答3:


Use a background worker or a new thread to run the heavy process and set the UI thread free. This helps you to update the UI even when the background process is running

Eg:

public void finishConfigButton_Click()
{
    worker = new BackgroundWorker();

    worker.DoWork += delegate(object s, DoWorkEventArgs args)
    {
        //Do the heavy work here
    };

    worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
    {
        //Things to do after the execution of heavy work
        validationProfile.IsBusy = false;
    };

    validationProfile.IsBusy= true;
    worker.RunWorkerAsync();
    }
}



回答4:


I finally figure it out. You can't use UI objects inside worker.DoWork block.I slightly modified the code and it now works.

 private void finishConfigButton_Click(object sender, RoutedEventArgs e)
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.WorkerSupportsCancellation = true;

        errorLabel.Visibility = System.Windows.Visibility.Collapsed;
        validationProfile.IsBusy = true;
        finishConfigButton.IsEnabled = false;
        backToLoginHyperlink.IsEnabled = false;

        bool validated = false;
        string newName = newNameTextBox.Text;
        string newEmail = newEmailTextBox.Text;
        string newUsername = newUsernameTextBox.Text;
        string newPassword = newPasswordPasswordBox.Password;
        string errorMessage = "Unknown error.";

        worker.DoWork += (o, ea) =>
        {
            if (newUser.ValidateNewUserInformation(newName, newEmail, newUsername, newPassword, ref errorMessage))
            {
                string activeDir = Environment.SystemDirectory.Substring(0, 1) + @":\Users\" + Environment.UserName + @"\My Documents\SSK\Users";
                string newPath = System.IO.Path.Combine(activeDir, newUser.Username);
                Directory.CreateDirectory(newPath);

                newUser.SaveUserData(newUser);

                newPath = System.IO.Path.Combine(activeDir, newUser.Username + @"\Settings");
                Directory.CreateDirectory(newPath);

                newUserSettings.SetDefaultValues();
                newUserSettings.SaveSettings(newUser, newUserSettings);

                validated = true;
            }
            else
                ea.Cancel = true;
        };

        worker.RunWorkerCompleted += (o, ea) =>
        {
            if (validated)
            {
                IntelliMonitorWindow intelliMonitor = new IntelliMonitorWindow(newUser, newUserSettings);
                intelliMonitor.Show();
                this.Close();
            }

            validationProfile.IsBusy = false;
            finishConfigButton.IsEnabled = true;
            backToLoginHyperlink.IsEnabled = true;
            errorLabel.Visibility = System.Windows.Visibility.Visible;
            errorLabel.Content = errorMessage;
        };

        worker.RunWorkerAsync();
    }


来源:https://stackoverflow.com/questions/9664391/showing-busy-indicator-control-inside-a-ui

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!