Обновить индикатор выполнения в MainWindow из другого потока - PullRequest
2 голосов
/ 11 декабря 2011

Я знаю, что этот вопрос задавался несколько раз, и я потратил целый день, пытаясь понять другие ответы, но, поскольку я очень плохо знаком с C # и WPF, мне пока ничего не помогло. Я постараюсь как можно точнее объяснить свою проблему, чтобы она мне напрямую помогла.

В моем MainWindow.xaml у меня есть индикатор выполнения и какая-то кнопка, запускающая новый поток и длинный расчет:

<ProgressBar Height="....... Name="progressBar1"/>
<Button Content="Button" Name="button1" Click="button1_Click" />

Теперь внутри моего MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        Thread thread = new Thread(new ParameterizedThreadStart(MyLongCalculation));

        ParameterClass myParameters = new ParameterClass();
        thread.Start(myParameters);
    }

    public void MyLongCalculations(object myvalues)
    {
        ParameterClass values = (ParameterClass)myvalues;
        //some calculations
    }
}

public class ParameterClass
{
    //public variables...
}

Теперь каким-то образом мне нужно включить что-то в мой метод MyLongCalculations, который будет постоянно обновляться progressBar1. Тем не менее, я просто не могу заставить его работать. Я знаю, что все это очень просто, но, к сожалению, это тот уровень, на котором я сейчас нахожусь с C #, поэтому я надеюсь, что ответ не слишком сложный и настолько подробный, насколько это возможно, было бы здорово.

Ответы [ 2 ]

3 голосов
/ 11 декабря 2011

Фоновый рабочий хорошо подходит для этого.

попробуйте это:

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        // Initialize UI
        InitializeComponent();

        // Process data
        ProcessDataAsync(new ParameterClass { Value = 20 });
    }

    /// <summary>
    /// Processes data asynchronously
    /// </summary>
    /// <param name="myClass"></param>
    private void ProcessDataAsync(ParameterClass myClass)
    {
        // Background worker
        var myWorker = new BackgroundWorker
        {
            WorkerReportsProgress = true,
        };

        // Do Work
        myWorker.DoWork += delegate(object sender, DoWorkEventArgs e)
        {
            // Set result
            e.Result = MyLongCalculations(myClass);

            // Update progress (50 is just an example percent value out of 100)
            myWorker.ReportProgress(50);
        };

        // Progress Changed
        myWorker.ProgressChanged += delegate(object sender, ProgressChangedEventArgs e)
        {
            myProgressBar.Value = e.ProgressPercentage;
        };

        // Work has been completed
        myWorker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e)
        {
            // Work completed, you are back in the UI thread.
            TextBox1.Text = (int) e.Result;
        };

        // Run Worker
        myWorker.RunWorkerAsync();
    }

    /// <summary>
    /// Performs calculations
    /// </summary>
    /// <param name="myvalues"></param>
    /// <returns></returns>
    public int MyLongCalculations(ParameterClass myvalues)
    {
        //some calculations
        return (myvalues.Value*2);
    }

}

/// <summary>
/// Custom class
/// </summary>
public class ParameterClass
{
    public int Value { get; set; }
}
0 голосов
/ 11 декабря 2011

Вы можете использовать Dispatcher.BeginInvoke () для отправки изменений пользовательского интерфейса в поток пользовательского интерфейса, а не рабочий поток. Самое главное - вам нужен доступ к Dispatcher, который связан с потоком пользовательского интерфейса, а не с рабочим потоком, который вы создаете вручную. Поэтому я хотел бы предложить кэш Dispatcher.Current и затем использовать в рабочем потоке, вы можете сделать это через ParametersClass или просто объявить поле dispatchr на уровне класса.

public partial class MainWindow
{
    private Dispatcher uiDispatcher;

    public MainWindow()
    {
        InitializeComponents();

        // cache and then use in worker thread method
        this.uiDispatcher = uiDispatcher;
    }

    public void MyLongCalculations(object myvalues)
    {
        ParameterObject values = (ParameterObject)myvalues;
        this.uiDispatcher.BeginInvoke(/*a calculations delegate*/);
    }
}

Также, если вам нужно передать диспетчер пользовательского интерфейса в какой-либо сервис / класс (например, ParametersClass), я бы посоветовал взглянуть на этот приятный SO-пост , который показывает, как вы можете абстрагировать его с помощью интерфейсов. с возможностью передавать изменения пользовательского интерфейса синхронно / асинхронно, так что это будет зависеть от вызывающей стороны (в основном используйте Invoke() или BeginInvoke() для постановки в очередь делегата в конвейере сообщений пользовательского интерфейса).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...