WPF C # Длительная операция - PullRequest
       12

WPF C # Длительная операция

2 голосов
/ 04 октября 2011

В основном у меня проблемы с потоками c # внутри wpf и с тем, как их правильно использовать.

Сначала я столкнулся с зависанием моего приложения из-за длительной работы.Изучив, как решить эту проблему, я решил использовать метод Dispatcher BeginInvoke и поместил запущенную операцию в свой собственный поток.Однако объем кода, который должен быть отправлен потоку пользовательского интерфейса, слишком велик, чтобы что-то изменить.

Вот упрощенная версия того, что я делаю, что вызывает зависание:

for (int i = 0; i < 5; i++)
{
    for (int j = 0; j < 100; j++)
    {
        for (int k = 0; k < 100; k++)
        {
            Image image = new Image();

            // ... Do stuff with image here 

            Binding binding = new Binding();

            // ... Bind some properties to the image

            // Add the image to a list and a canvas
            List.Add(image);
            SomeCanvas.Children.Add(image);
        }
    }
}

Как вы видите, большая часть обработки в операции состоит из использования элементов управления.Поэтому они должны передаваться потоку пользовательского интерфейса асинхронно.После этого в основном все операции выполняются в потоке пользовательского интерфейса, и снова приложение зависает: /

Есть предложения о том, что я могу сделать в этой ситуации?Большое спасибо

Ответы [ 4 ]

1 голос
/ 04 октября 2011

Создание такого большого количества визуальных объектов в узком цикле обязательно будет вялым. Возможно, вы могли бы попытаться разделить это на две фазы. Внутри вашей тесной петли вы просто создаете заполнитель для изображения. Скажите прямоугольник с заполненным цветом, чтобы указать, где изображение будет показано в будущем.

Затем в другом наборе потоков вы фактически загружаете содержимое изображений и устанавливаете привязки. Таким образом, пользовательский интерфейс всегда остается откликом. Пользователь сразу видит заполнители, а затем видит, что фактические изображения заменяют заполнители по мере их загрузки в режиме реального времени. Вы постоянно видите это на веб-страницах, где заполнители заполняются фактическим содержимым при его загрузке.

0 голосов
/ 04 октября 2011

Вы можете убедиться, что обработка, требуемая для потока пользовательского интерфейса, обрабатывается во время простоя, т. Е. Когда он не обрабатывает события и т. Д.

Это выполняется с помощью установки приоритета System.Windows.Threading.DispatcherPriority.SystemIdleпри отправке операции.

Эта ссылка должна предоставить необходимую информацию (обозначение однопоточного приложения с длительным расчетом)

Это, безусловно, уменьшит скорость, с которой вашобработка завершается, но это позволит вам поддерживать полностью функциональный пользовательский интерфейс во время обработки.

0 голосов
/ 04 октября 2011

Вот пример, создающий большое количество объектов пользовательского интерфейса асинхронно:

public partial class Window1 : Window
    {
        public delegate void CreateCanvasHandler(Grid parent, int index);

        public Window1()
        {
            InitializeComponent();

            int count = 10000;

            this.TestCreateAsync(count);
        }

        private void TestCreateAsync(int count)
        {
            for (int i = 0; i < count; i++)
            {
                //check the DispatecherOperation status
                this.LayoutRoot.Dispatcher.BeginInvoke(new CreateCanvasHandler(this.CreateCanvas),
                    DispatcherPriority.Background,
                    new object[2] 
                    { 
                        this.LayoutRoot,
                        i
                    });   
            }
        }

        private void CreateCanvas(Grid parent,
            int index)
        {
            Canvas canvas = new Canvas()
            {
                Width = 200,
                Height = 100
            };

            canvas.Children.Add(new TextBlock()
            {
                Text = index.ToString(),
                FontSize = 14,
                Foreground = Brushes.Black
            });

            Thread.Sleep(100);

            parent.Children.Add(canvas);
        }
    }
0 голосов
/ 04 октября 2011

Вы, конечно, не используете все ядра современного процессора, выполняя все в потоке пользовательского интерфейса.

Похоже, вы обрабатываете несколько изображений из потока пользовательского интерфейса.Я подозреваю, что обработка изображений - это интенсивная загрузка процессора, а не другие элементы, на которые намекает ваш пример кода.Если это так, подумайте о том, чтобы выполнить манипуляции с изображениями в нескольких различных потоках и заставить поток пользовательского интерфейса делать то, что ему нужно, после завершения каждого рабочего потока.

Если вы можете использовать .NET 4, Task Parallel Library позволяет очень легко работать с потоками.Я считаю BlockingCollection очень полезным для координации работы между потоком пользовательского интерфейса и рабочими потоками.В приведенной мною ссылке есть хорошие примеры кода.

...