不同线程上的wpf屏幕“随机”冻结

时间:2013-10-17 06:23:23

标签: c# wpf multithreading wpftoolkit

我有一个问题,我已经有一个多星期了,我无法弄明白为什么。

我有一个等待屏幕,我放在一个不同的线程中,所以它可以加载并显示它的自我,即使代码正在做大量的工作(当我在同一个线程中做了什么,屏幕不会显示它的自我,我认为那是因为代码是忙于做其他的事情)

然而,它并不总是冻结一段时间,只在平板电脑上,它在我的电脑上工作正常(至少我没有注意到它在我的电脑上测试时冻结)。

我试图“破解”其中的一些变通方法,例如在等待屏幕上放置一个取消按钮,这样它就可以关闭但是无法点击它(如果冻结并且没有响应)

1次我也认为它给出了问题,因为我会在线程启动之前关闭它所以我做了一个布尔值,如果线程仍在加载或者不是如果它并且我试图关闭它我会说它会添加一个事件列表器,以便在线程完成启动时关闭它。

无论如何这里是代码,我希望有人可以帮助我。

public partial class WaitWindow : Window
{
    //private static WaitWindow ww = new WaitWindow();
    private static Thread thread;
    private static event ThreadStartingEvent started;
    private delegate void ThreadStartingEvent(object sender, EventArgs e);
    public static bool disposable = false;

    private static bool startingThread;
    private static bool StartingThread
    {
        get
        {
            return startingThread;
        }
        set
        {
            startingThread = value;
            if (!startingThread && started != null)
            {
                started(null, new EventArgs());
            }
        }
    }

    // To refresh the UI immediately
    private delegate void RefreshDelegate();
    private static void Refresh(DependencyObject obj)
    {
        obj.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render,
            (RefreshDelegate)delegate { });
    }

    public WaitWindow()
    {
        InitializeComponent();
    }

    public static void BeginDisplay()
    {
        if (thread == null)
        {
            startingThread = true;
            thread = new Thread(() =>
            {
                WaitWindow ww = new WaitWindow();
                ww.Show();


                ww.Closed += (sender2, e2) =>
                ww.Dispatcher.InvokeShutdown();
                System.Windows.Threading.Dispatcher.Run();
            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            startingThread = false;
        }
    }

    public static void EndDisplay()
    {
        if (startingThread)
        {
            started += new ThreadStartingEvent(WaitWindow_started);
        }
        if (thread != null)
        {
            disposable = false;
            thread.Abort();
            thread = null;
        }
    }

    static void WaitWindow_started(object sender, EventArgs e)
    {
        thread.Abort();
        thread = null;
        started = null;
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        if (disposable)
        {
            disposable = false;
            thread.Abort();
            thread = null;
        }
    }
}

和xaml代码:

<Window x:Class="WpfApplication1.WaitWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
    Title="WaitWindow" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation="CenterScreen"
    Background="Transparent" AllowsTransparency="True" 
        Width="1024" Height="640">
    <Grid>
        <xctk:BusyIndicator Name="BusyBar" IsBusy="True" BusyContent="Even geduld a.u.b.">
        </xctk:BusyIndicator>
        <Button Name="button1" Width="28" HorizontalAlignment="Left" Margin="550,271,0,0" Height="28" VerticalAlignment="Top" Click="button1_Click">X</Button>
    </Grid>
</Window>

maby一些额外的信息:当我正在做可能需要一些时间的任务(从远程数据库获取数据)时,我打电话给BeginDisplay(),当代码完成后,我打电话给EndDisplay() 这对我来说似乎相当明显,但我认为提及它没什么坏处。

编辑: 我应该提一下我正在使用.net framework 3.5

2 个答案:

答案 0 :(得分:0)

如果您正在执行后台异步任务,则需要创建SynchronizationContext。也许这就是问题的原因?

// Create a thread
Thread newWindowThread = new Thread(new ThreadStart( () =>
{
    // Create our context, and install it:
    SynchronizationContext.SetSynchronizationContext(
        new DispatcherSynchronizationContext(
            Dispatcher.CurrentDispatcher));

    Window1 tempWindow = new Window1();
    // When the window closes, shut down the dispatcher
    tempWindow.Closed += (s,e) => 
       Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);

    tempWindow.Show();
    // Start the Dispatcher Processing
    System.Windows.Threading.Dispatcher.Run();
}));

// Set the apartment state
newWindowThread.SetApartmentState(ApartmentState.STA);
// Make the thread a background thread
newWindowThread.IsBackground = true;
// Start the thread
newWindowThread.Start();

此代码受到this blog article的限制,值得一读。

答案 1 :(得分:0)

通常情况下,您会将锁定UI的处理移至后台线程,并保持主线程免费用于Dispatcher.Invoke()返回的所有UI更新,因此您在此处拥有的内容非常不同的实施。

我跳出来的第一件事就是使用Thread.Abort()我很确定MSDN文档基本上说不要使用它,除非你的线程没有其他停止方法。特别是,如果您已经中止了线程,那么将要关闭打开的窗口。这可能是你的问题吗?