Вопрос о многопоточности относительно WPF - PullRequest
1 голос
/ 30 декабря 2010

Я новичок в многопоточности, и я действительно не знаю, как кодировать конкретную задачу. Я хотел бы обработать событие щелчка мыши на окне, которое запустит цикл while в отдельном потоке. Этот поток, отличный от потока пользовательского интерфейса, должен вызывать функцию в цикле while, которая обновляет метку в окне, обслуживаемом потоком пользовательского интерфейса. Цикл while должен прекратиться, когда левая кнопка мыши больше не нажимается. Все, что делает цикл - это увеличивает счетчик, а затем повторно вызывает функцию, которая отображает обновленное значение в окне. Код для окна и всех потоков приведен ниже (я получаю некоторую ошибку о STA-потоках, но не знаю, куда поместить атрибут). Кроме того, я надеюсь использовать это решение, если оно когда-нибудь будет работать, в другом проекте, который выполняет асинхронные вызовы службы в другом месте через wcf, поэтому я надеялся не создавать никаких специальных конфигураций для всего приложения, поскольку я действительно нов многопоточности и я очень обеспокоен нарушением другого кода в более крупной программе ... Вот что у меня есть:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        Name="MyMainWindow"
        Title="MainWindow" Width="200" Height="150"
        PreviewMouseLeftButtonDown="MyMainWindow_PreviewMouseLeftButtonDown">
    <Label Height="28" Name="CounterLbl" />
</Window>

А вот код позади:

using System.Windows;
using System.Windows.Input;
using System.Threading;

namespace WpfApplication2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private int counter = 0;

        public MainWindow()
        {
            InitializeComponent();
        }

        private delegate void EmptyDelegate();

        private void MyMainWindow_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Thread counterThread = new Thread(new ThreadStart(MyThread));

            counterThread.Start();
        }

        private void MyThread()
        {
            while (Mouse.LeftButton == MouseButtonState.Pressed)
            {
                counter++;

                Dispatcher.Invoke(new EmptyDelegate(UpdateLabelContents), null);
            }
        }

        private void UpdateLabelContents()
        {
            CounterLbl.Content = counter.ToString();
        }
    }
}

В любом случае, многопоточность действительно нова для меня, и у меня нет никакого опыта в ее реализации, поэтому любые мысли и предложения приветствуются!

Спасибо

Andrew

Изменить:

Вот еще одна версия (я также добавил сетку) с использованием BackgroundWorker, которая все еще жалуется, что вызывающий поток должен быть STA ...

<Window x:Class="WpfApplication2.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1"
        Name="MyMainWindow" Width="200" Height="150" PreviewMouseLeftButtonDown="MyMainWindow_PreviewMouseLeftButtonDown">
    <Grid>
        <Label Height="28" Name="CounterLbl" />
    </Grid>
</Window>

и код позади ...

using System.Windows;
using System.Windows.Input;
using System.Threading;
using System.ComponentModel;

namespace WpfApplication2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private int counter = 0;

        public Window1()
        {
            InitializeComponent();
        }

        private delegate void EmptyDelegate();

        private void MyMainWindow_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += new DoWorkEventHandler(MyThread);
            bw.RunWorkerAsync(this);
        }

        private void MyThread(object sender, DoWorkEventArgs e)
        {
            Window window = e.Argument as Window;

            while (Mouse.LeftButton == MouseButtonState.Pressed)
            {
                counter++;

                window.Dispatcher.Invoke(new EmptyDelegate(UpdateLabelContents), null);
            }
        }

        private void UpdateLabelContents()
        {
            CounterLbl.Content = counter.ToString();
        }
    }
}

1 Ответ

2 голосов
/ 30 декабря 2010

Для простоты используйте BackgroundWorker

Этот ответ SO: Является ли этот рабочий поток / фоновый рабочий для приложения CF WPF в порядке? имеет другие рекомендации, хотя в вашем случае BackgroundWorker, похоже, хорошо подходит, особенно из-за требования ProgressChanged.

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