2016-02-18 67 views
0

我有一個代碼,它有一個文本框和一個按鈕,當我按下按鈕時,代碼更新文本框,並且在單詞睡眠5秒後,被凍結 我試圖與代表,和線程但沒有任何工程 這是代表代碼:嘗試更新wpf中的文本框時UI會凍結

MainWindow.vb

Class MainWindow 
    Delegate Sub MySubDelegate(ByVal x As String) 
    Private m_engine As Engine 

    Public Sub New() 
     m_engine = New Engine(AddressOf WriteToLog) 
     InitializeComponent() 
     Me.DataContext = m_engine.GetViewModel() 

    End Sub 

    Public Sub WriteToLog(str As String) 
     Dim vv As ViewModel = CType(DataContext, ViewModel) 
     vv.Log = str 
    End Sub 

    Private Sub clicked(sender As Object, e As RoutedEventArgs) 
     m_engine.TimingRecord() 
    End Sub 
End Class 

Engine.vb

Private m_viewModel As New ViewModel 
Private _msd As MainWindow.MySubDelegate 

Public Sub New() 

End Sub 

Sub New(msd As MainWindow.MySubDelegate) 
    _msd = msd 
End Sub 

Public Function GetViewModel() As ViewModel 
    Return m_viewModel 
End Function 

Public Sub TimingRecord()   
    _msd("aaaaa") 
    SetText() 
End Sub 


Public Sub SetText() 
    Thread.Sleep(5000) 
End Sub 

viewModel.vb

Public Class ViewModel 
    Implements INotifyPropertyChanged 
    Private m_log As String 
    Public Property Log As String 
     Get 
      Return m_log 
     End Get 
     Set(value As String) 
      m_log = value 
     End Set 
    End Property 
    Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged 
    Private Sub NotifyPropertyChanged(Optional ByVal propertyName As String = Nothing) 
      RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName)) 
    End Sub 
End Class 

這與線程的代碼:

MainWindow.vb

Delegate Sub MySubDelegate(ByVal x As String) 
Private m_engine As Engine 

Public Sub New() 
    m_engine = New Engine(AddressOf WriteToLog) 
    InitializeComponent() 
    Me.DataContext = m_engine.GetViewModel() 

End Sub 

Public Sub WriteToLog(str As String) 
    Me.Dispatcher.Invoke(Sub() CType(DataContext, ViewModel).Log = str) 
    'Dim vv As ViewModel = CType(DataContext, ViewModel) 
    'vv.Log = str 
End Sub 

Private Sub clicked(sender As Object, e As RoutedEventArgs) 
    m_engine.TimingRecord() 
End Sub 

Engine.vb

Public Class Engine 
    Private m_viewModel As New ViewModel  
    Private m_thread As Thread 
    Private _msd As MainWindow.MySubDelegate 

    Public Sub New(msd As MainWindow.MySubDelegate) 
     _msd = msd 
    End Sub 

    Public Function GetViewModel() As ViewModel 
     Return m_viewModel 
    End Function 

    Public Sub TimingRecord() 
     m_thread = New Thread(AddressOf DoRecordThread) 
     m_thread.IsBackground = True 
     m_thread.Start("aa") 
     SetText() 
    End Sub 

    Public Sub SetText() 
     Thread.Sleep(5000) 
    End Sub 

    Private Sub DoRecordThread(str As String) 
     _msd(str) 
     'm_viewModel.Log = str 
    End Sub 
End Class 

視圖模型保持不變。我使用wpf,因此我將日誌綁定到文本框中,並使用簡單的代碼工作。

謝謝大家提前。

+1

'SLEEP'導致你的線程好,睡吧。如果線程是你的用戶界面,那麼它就完全按照你所說的去做。 – Steve

+0

你爲什麼要做'Thread.Sleep(5000)'? – Enigmativity

+0

謝謝你的回覆,thread.sleep來代替一個很長的運行,從1到100000000,我把睡眠放在新的線程裏面,用戶界面沒有凍結,但是他的文本框沒有更新,你能幫我嗎 – Joe

回答

1

Thread.Sleep導致該問題。它會阻止使UI凍結的UI線程。

在不同的線程中執行長時間運行的任務,並且一旦完成更新UI(TextBox)與Application.Current.Dispatcher

示例代碼與Dispatcher更新從後臺線程的UI:

Application.Current.Dispatcher.Invoke(new Action(() => { Textbox1.Text = result; })) 

這不是一個正確的做法,但我希望這是你在找什麼。

更新

此外,還有另一種方式,你可以使用內置BackgroundWorker

//Add the namespace 
using System.ComponentModel; 

//Declare 
private readonly BackgroundWorker worker = new BackgroundWorker(); 

//Initialize 
worker.DoWork += worker_DoWork; 
worker.ProgressChanged += worker_ProgressChanged; 
worker.RunWorkerCompleted += worker_RunWorkerCompleted; 


//method declaration 
private void worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    worker.ReportProgress(0, "Process started"); 
    // run all background tasks here 
} 

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    //Progress update with e.UserState.ToString(); 
} 

private void worker_RunWorkerCompleted(object sender, 
             RunWorkerCompletedEventArgs e) 
{ 
    //update ui once worker complete his work 
} 

//Invoke 
worker.RunWorkerAsync(); 
+0

是的將thread.sleep放入新線程中可以解決凍結問題,但文本不會更新,並且我希望在長時間運行之前寫入文本的可能性(如將「啓動進程」寫入日誌文本框) – Joe

+0

你可以在新的線程裏面添加代碼'Application.Current.Dispatcher.Invoke(new Action(()=> {Textbox1.Text = result;}))''來更新文本。 – Gopichandar

+0

@Joe。 。看到我更新的答案。 。 – Gopichandar

0

通過放了Thread.Sleep但在視圖模型類的我不小心刪除了,現在更改屬性,它正在完美非常愚蠢的我解決的問題謝謝大家的幫助