I have created a Window with a TextBlock inside. I have bound the Text property and everything works fine. BUT When I change the bounded property while inside a Task then nothing works!!
Do you know why?
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
text 2 and 3 are never shown. If I change dynamically the Text of the textblcok(ex : m_oView.txtLoadingText.Text) It works fine(but it's mnot a solution)
EDIT This is the ViewModel Base, every ViewModel implements that Class.
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
How StartProgress is Called:
<i:Interaction.Triggers>
     <i:EventTrigger EventName="ContentRendered">
         <i:InvokeCommandAction Command="{Binding DataContext.WindowsActivatedCommand,ElementName=fLoading}" />
     </i:EventTrigger>
 </i:Interaction.Triggers>
EDIT Binding TextBlock to Property
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>
                You need to implement INotifyPropertyChanged on your view model type, and have the LoadingText setter raise that event.
Here's a detailed answer on what you need to do to make sure calls that originate on non-UI threads invoke UI methods properly:
Ensuring that things run on the UI thread in WPF
@ Manolis Xountasis,
I do not know VB.net, but I test code in C#, it is ok. Below is my code:
    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>
Hope this code is useful for you.
According to this page (emphasis mine):
Now this might scare you off the C# asynchronous language features, because it makes them seem slow, but this is not a fair test. The reason this takes so much longer is that we’ve given the program much more work to do. When the simple, synchronous version runs on the UI thread, WPF does very little immediate work for each item we add to the LogUris collection. Data binding will detect the change—we’ve bound a ListBox to that collection, so it’ll be looking for change notification events—but WPF won’t fully process those changes until our code has finished with the UI thread. Data binding defers its work until the dispatcher thread has no higher priority work to do.
That may be the reason why it works if you update the property via the dispatcher. Have you try to force an update in the target via GetBindingExpression(Property).UpdateTarget()2 ?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With