2013-06-24 101 views
6

我創建了一個帶有TextBlock的窗口。我綁定了Text屬性,一切正常。 但是 當我在一個任務內改變有界屬性時,沒有任何工作!綁定和異步操作

你知道爲什麼嗎?

Public Async Sub StartProgress() 
    Try 
     LoadingText = "text 1" 'Works perfect 

     Dim fResult As Boolean = Await LoadModules() 

     If Not fResult Then 
      MessageBox.Show(Me.Error) 
     End If 

     m_oView.Close() 
    Catch ex As Exception 
     Msg_Err(ex) 
    End Try 
End Sub 

Public Async Function LoadModules() As Task(Of Boolean) 
    Try 
     Await Task.Delay(3000) 

     LoadingText = "text 2" 'Nothing Happens 

     Await Task.Delay(5000) 

     LoadingText = "complete" 'Nothing Happens 

     Await Task.Delay(3000) 

     Return True 
    Catch ex As Exception 
     Me.Error = ex.Message 
     Return False 
    End Try 
    End Function 

文本2和3從不顯示。如果我動態改變textblcok(例如:m_oView.txtLoadingText.Text)的文本,它工作正常(但它是mnot的解決方案)

編輯 這是視圖模型基地,每個視圖模型實現了類。

Public Class VM_Base 
    Implements IDisposable 
    Implements INotifyPropertyChanged 

    Private m_oDS As MxDataSet 
    Public Property [Error] As String 

    Public Event PropertyChanged As PropertyChangedEventHandler _ 
     Implements INotifyPropertyChanged.PropertyChanged 

    Protected Sub New() 
     m_oDS = New MxDataSet 

    End Sub 

    Protected Overrides Sub Finalize() 
     Try 
      Me.Dispose(False) 
      Debug.Fail("Dispose not called on ViewModel class.") 
     Finally 
      MyBase.Finalize() 
     End Try 
    End Sub 

    Public Sub Dispose() Implements IDisposable.Dispose 
     Me.Dispose(True) 
     GC.SuppressFinalize(Me) 
    End Sub 

    Protected Overridable Sub Dispose(disposing As Boolean) 
    End Sub 

    Protected Overridable Sub OnPropertyChanged(propertyName As String) 
     Me.EnsureProperty(propertyName) 
     RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName)) 
    End Sub 

    <Conditional("DEBUG")> _ 
    Private Sub EnsureProperty(propertyName As String) 
     If TypeDescriptor.GetProperties(Me)(propertyName) Is Nothing Then 
      Throw New ArgumentException("Property does not exist.", "propertyName") 
     End If 
    End Sub 
End Class 

StartProgress怎麼叫:

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="ContentRendered"> 
     <i:InvokeCommandAction Command="{Binding DataContext.WindowsActivatedCommand,ElementName=fLoading}" /> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

編輯 綁定TextBlock的物業

Public Property LoadingText As String 
    Get 
     Return m_sLoadingText 
    End Get 
    Set(value As String) 
     m_sLoadingText = value 
     OnPropertyChanged("LoadingText") 
    End Set 
End Property 
<TextBlock x:Name="txtLoading" Width="450" 
      Grid.Row="1" VerticalAlignment="Center" 
      HorizontalAlignment="Left" 
      TextWrapping="Wrap" Text="{Binding LoadingText}"> 
    </TextBlock> 

回答

1

這裏有你需要做的,以確保有什麼詳細的解答來自非UI線程的調用調用UI方法s請正確:

Ensuring that things run on the UI thread in WPF

+0

我沒有任何錯誤,當我嘗試設置文本屬性的構造函數。此外,我使用Task,無論是Dispatcher還是BackgroundWorker,以關注調用UI。另外,如果我強制TextBlock更改文本,例如m_oView.txtLoadingText.Text =「something」,那麼它會改變! –

1

您需要實現INotifyPropertyChanged您的視圖模型類型,並有LoadingText二傳手提高該事件。

+0

我已經這樣做了。來自Task之外的代碼,如LoadingText =「text 1」完美的作品。任務內的代碼不起作用! –

+0

我懷疑'StartProgress'被稱爲初始化的一部分。在這種情況下,綁定會在你設置「LoadingText」之後生效。當你的'async'方法稍後恢復時,* update *失敗。這完全表明了一個不正確的'INotifyPropertyChanged'實現。 –

+0

我編輯了我的帖子,以瞭解我如何實現INotifyPropertyChanged以及如何調用StartProgress。你能看看嗎? –

1

@馬諾利斯Xountasis,

我不知道VB.net,但我在C#中測試代碼,它是確定。下面是我的代碼:

public partial class MainWindow : Window 
{ 
    private TestViewModel _tvm = new TestViewModel(); 

    public MainWindow() 
    { 
     InitializeComponent(); 

     this.wndTest.DataContext = _tvm; 

     _tvm.TestData = "First Data"; 

     this.btnAsync.Click += BtnAsyncOnClick; 
    } 

    private void BtnAsyncOnClick(object sender, RoutedEventArgs routedEventArgs) 
    { 
     var task = Task.Factory.StartNew(() => this.Dispatcher.Invoke(new Action(() => _tvm.TestData = "changed data"))); 
    } 
} 


<Window 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="clr-namespace:WpfApplication3" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" 
x:Class="WpfApplication3.MainWindow" 
x:Name="wndTest" 
Title="MainWindow" 
Height="350" 
Width="525"> 
<!--<Window.Resources> 
    <local:TestViewModel x:Key="TestViewModelDataSource" d:IsDataSource="True"/> 
</Window.Resources> 
<Window.DataContext> 
    <Binding Mode="OneWay" Source="{StaticResource TestViewModelDataSource}"/> 
</Window.DataContext>--> 
<Grid> 
    <TextBox HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Text="{Binding TestData}" /> 
    <Button x:Name="btnAsync" Content="Change Async" HorizontalAlignment="Right" VerticalAlignment="Top"/> 
</Grid> 

希望這個代碼是對您有用。

+0

您使任務調用調度程序,這意味着它不是「真正」異步(認爲我的功能將需要大約1-2分鐘才能完成)。當我們調用PropertyChange(「something」)時,也會通過文檔檢查是否需要調用控件。我不覺得它完成了我的要求。謝謝你的時間!! –

1

根據這個page(重點煤礦):

現在,因爲這讓他們看起來慢,但是這是一個不公平的測試,這可能嚇跑你的C#異步語言功能, 。這需要很長時間的原因是我們已經給程序多了許多工作要做。當線程的UI 上運行簡單的同步版本時,WPF爲我們添加到LogUris集合的 的每個項目執行的任務很少。 數據綁定將檢測到更改 - 我們將綁定到該集合的ListBox,因此它將尋找更改 通知事件 - 但WPF將不會完全處理這些更改,直到 我們的代碼已完成與UI線程。數據綁定推遲其工作 ,直到調度程序線程沒有更高優先級的工作要做。

這可能是它通過調度程序更新屬性的原因。您是否嘗試通過GetBindingExpression(Property).UpdateTarget()2強制更新目標?

+0

我沒有..我會試一試,我會通知你!謝謝你的時間。 –

0

Nowdays你可以像這樣

表/窗口

btnAddNewCard.Click += async (s, e) => await BtnAddNewCard_ClickAsync(s, e); 


private async Task BtnAddNewCard_ClickAsync(object sender, RoutedEventArgs e) 
{ 
    // Any code like 
    await ShowOKMessageAsync(msg);     
}