2013-10-17 39 views
0

我有一個問題,我已經有一個多星期了,我無法弄清楚爲什麼。wpf屏幕在不同的線程上'隨機'凍結

我有一個等待的屏幕,我放在不同的線程中,所以它可以加載並顯示它的自我,即使代碼正在執行大量工作(當我在同一個線程中執行evrything屏幕不顯示它是自我,我認爲這是因爲代碼是忙於做其他的東西)

然而,它並不總是隻是在平板上凍結一段時間,它在我的電腦上工作正常(至少我沒有注意到它在我的電腦上測試時凍結)。

我試圖「破解」一些解決方法在裏面,例如將取消等待屏上的按鈕,以便它可以被關閉,但它不能被點擊(阿西夫它凍結和沒有響應)

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> 

莫比一些額外的信息:當我在做這可能需要一些時間(從遠程數據庫獲取數據)我叫BeginDisplay()和代碼時任務我打電話給EndDisplay() 這對我來說似乎相當明顯,但我想提起它並沒有什麼壞處。

編輯: 我應該提我使用的.NET Framework 3.5

+1

我在代碼中看不到問題。也許您正在使用的平板電腦僅具有較弱的CPU並且很忙?作爲一個方面說明,你可以通過使用'Window.ShowDialog()'來真正簡化你的代碼,那麼你就不需要'Dispatcher.Run()'(或關閉)。另外,不要放棄線程,而應該保持對該窗口的引用,並且只需「關閉()」它。 –

+0

我對跨線程並不擅長,我怎樣才能做到這一點,所以我可以從主線程(這不是它創建的線程?)ww.close() – Vincent

+0

只需將窗口保存爲成員並然後調用_win.Dispatcher.InvokeAsync(()=> _win。關閉());' –

回答

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捏,這是值得一讀的。

0

通常情況下,你會移動被鎖定UI開了一個後臺線程的處理,並保持主線程免費爲您找回由Dispatcher.Invoke(),所以你在這裏的是一個非常不同的實現所有UI更新。

跳出來的第一件事就是使用Thread.Abort()我非常確定MSDN文檔基本上說不要使用它,除非你的線程沒有其他停止方法。特別是,如果您中止了線程,將會留下什麼來關閉打開的窗口。這可能是你的問題嗎?

+0

你會推薦什麼其他方式關閉線程? – Vincent

+0

無,而是在消息泵Dispatcher.Run()完成時關閉它。簡而言之,@詹姆斯世界已經回答了代碼。 – AlSki