多线程冻结UI

时间:2016-02-26 08:54:38

标签: wpf multithreading

我有一个mutlithreaded WPF应用程序。但是在启动一些后台线程之后,UI处于冻结状态(显示和UI输入)。 这是一个简化(但完整)的例子:

<Window x:Class="WPF_Multithreading.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>

    <ListBox ItemsSource="{Binding Path=Scores, UpdateSourceTrigger=PropertyChanged}"/>
    <ListBox Grid.Column="1" ItemsSource="{Binding Path=FrameRates, UpdateSourceTrigger=PropertyChanged}"/>

    <Button Grid.Row="1"
        Content="New Thread" Click="Button_NewThread_Click" />
    <Button Grid.Row="1" Grid.Column="1"
            Content="UI test" Click="Button_UItest_Click"/>
</Grid>
</Window>

代码隐藏:

using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Threading;

namespace WPF_Multithreading
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    private List<Thread> threads;

    ObservableCollection<int> _scores;
    public ObservableCollection<int> Scores
    {
        get { return _scores; }
        set { _scores = value; RaisePropertyChanged("Scores"); }
    }

    ObservableCollection<int> _framerates;
    public ObservableCollection<int> FrameRates
    {
        get { return _framerates; }
        set { _framerates = value; RaisePropertyChanged("FrameRates"); }
    }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;

        Scores = new ObservableCollection<int>();
        FrameRates = new ObservableCollection<int>();
        threads = new List<Thread>();
    }

    ~MainWindow()
    {
        foreach (Thread t in threads) t.Abort();
    }

    private void Button_NewThread_Click(object sender, RoutedEventArgs e)
    {
        Thread t = new Thread(backgroundRun);

        Scores.Add(0);
        FrameRates.Add(0);
        t.Start(this);
        threads.Add(t);

    }

    private void backgroundRun(object o)
    {
        MainWindow _this = (MainWindow)o;

        int index = _this.Scores.Count()-1;
        Random r = new Random();

        DateTime prevDT = DateTime.Now;

        int nbiterations = 0;

        while(true)
        {
            // simulate computation
            nbiterations = 0;
            while((DateTime.Now-prevDT).Milliseconds < 50)
            {
                nbiterations++;
            }

            // Update UI
            Dispatcher.Invoke(() =>
                {
                    _this.Scores[index] = nbiterations;// r.Next();
                    _this.FrameRates[index] = (DateTime.Now - prevDT).Milliseconds;
                });

            prevDT = DateTime.Now;
        }
    }

    private void Button_UItest_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("UI input ok");
    }

}
}

在这个例子中,我必须启动很多线程才能使UI冻结,但在我更复杂的应用程序(显示2D图形)中,只有2或3个线程可以实现(有时冻结超过10秒)。
我的问题是:有没有办法确保Dispatcher有足够的资源来解冻UI(尤其是输入)?

0 个答案:

没有答案