2016-05-07 3 views
0

Я относительно новичок в проектах C# WPF, и у меня есть проблема с моим кодом, благодаря чему пользовательский интерфейс «блокируется», пока я выполняю задачу. Вот соответствующий код:Предотвращение зависания GUI в WPF

public partial class MainWindow : Window { 

    // handles to ManagedDLAContainer objects 
    private ManagedDLA2DContainer dla_2d; 

    public MainWindow() { 
     InitializeComponent(); 

     // initalise aggregate containers 
     dla_2d = new ManagedDLA2DContainer(); 
    } 

    private void GenerateAggregate() { 
     // generate the 2D aggregate of size given by particles_slider value 
     Dispatcher.Invoke(new Action(() => { dla_2d.Generate((uint)particles_slider.Value); })); 

     // TODO: add particles to "canvas" on GUI as they are generated 
    } 

    private void GenerateButtonClick(object sender, RoutedEventArgs e) { 
     // set the coefficient of stickiness of aggregate 
     // to current value of stickiness_slider 
     dla_2d.SetCoeffStick(stickiness_slider.Value); 

     // start asynchronous task calling GenerateAggregate method 
     Task.Factory.StartNew(() => GenerateAggregate()); 
    } 

} 

ManagedDLA2DContainer Вот это управляемый C++/CLI обертка для какого-то родного, неуправляемого C++ кода и stickiness_slider просто Slider элемента интерфейса WPF; в то время как аналогичным образом particles_slider является другим элементом Slider интерфейса. Должен отметить, что следующий код также приводит к GUI подвешивания:

public partial class MainWindow : Window { 

    // lock object for multi-threading tasks 
    private static readonly object locker = new object(); 

    // handles to ManagedDLAContainer objects 
    private ManagedDLA2DContainer dla_2d; 

    public MainWindow() { 
     InitializeComponent(); 

     // initalise aggregate containers 
     dla_2d = new ManagedDLA2DContainer(); 
    } 

    private void GenerateAggregate() { 
     // lock around aggregate generation 
     lock (locker) { 
      // generate the 2D aggregate of size given by particles_slider value 
      Dispatcher.Invoke(new Action(() => { dla_2d.Generate((uint)particles_slider.Value); })); 

      // TODO: add particles to "canvas" on GUI as they are generated 
     } 
    } 

    private void GenerateButtonClick(object sender, RoutedEventArgs e) { 
     // set the coefficient of stickiness of aggregate 
     // to current value of stickiness_slider 
     dla_2d.SetCoeffStick(stickiness_slider.Value); 

     Thread agg_gen_thread = new Thread(GenerateAggregate); 
     agg_gen_thread.Start(); 
     agg_gen_thread.Join(); 
    } 

} 

Любая информация, которая может помочь мне понять, что я могу делать неправильно здесь ценится.

Кроме того, если вам интересно, то весь код для этого проекта можно посмотреть здесь: https://github.com/SJR276/DLAProject

ответ

1

Вы начинаете новый поток, в котором выполняется GenerateAggregate. Затем немедленно отправляйте всю работу назад в пользовательский интерфейс через Dispatcher.Invoke. Таким образом, в основном вы выполняете длительную работу над потоком пользовательского интерфейса и блокируете его.

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

Предположим, ваша функция Generate выглядит следующим образом:

void Generate() { 
    MakeCpuIntensiveWork(); 
    UpdateUIWithResults(); 
} 

Вам нужно только направить вторую часть в UI потоке. В вашем случае, как мы выяснили в комментариях, единственная часть пользовательского интерфейса получает значение слайдера. Таким образом, вы можете разделить так:

private void GenerateAggregate() 
{ 
    uint sliderValue = 0; 
    // generate the 2D aggregate of size given by particles_slider value 
    Dispatcher.Invoke(() => { sliderValue = (uint)particles_slider.Value; }); 
    dla_2d.Generate(sliderValue); 
    // TODO: add particles to "canvas" on GUI as they are generated 
} 
+0

Без 'Dispatcher.Invoke' я получаю исключение времени выполнения о том, что вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет. Кроме того, 'GenerateAggregate' будет добавлять элементы в GUI (в конечном итоге), поэтому я понимаю, что мне нужно использовать' Dispatch.Invoke'. – ArchbishopOfBanterbury

+0

Вам нужно отправить _only_ части, которые обновляют элементы управления пользовательским интерфейсом, а не весь метод. – Evk

+0

А, я вижу, это имеет смысл. Я должен отметить: 'Generate' - это метод класса ManagedDLA2DContainer, который является кодом C++/CLI; действительно ли возможно обновить пользовательский интерфейс из оболочки C++/CLI? – ArchbishopOfBanterbury

Смежные вопросы