How to update the user interface when running long-time functions in WPF?

奇 卢 181 Reputation points
2021-05-12T06:21:37.95+00:00

In the form, I define a TextBlock object through XAML code and bind it to my custom attribute "Val". When running a long-time function, "Val" is constantly updated, but it is not updated to the form interface in real time. How to make the form interface update data in real time?(“ Val has implemented the INotifyPropertyChanged interface in its class.

...
<TextBlock Text="{Binding ElementName=myClass,Path=Val}"/>
...
...

.....
public int Val{
.....
}

public void LongTime(){
    for(int i=0;i<10000000;i++){
           if(i%1000==0)
                 Val++;
     }
}
......
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,635 questions
0 comments No comments
{count} votes

Accepted answer
  1. DaisyTian-1203 11,611 Reputation points
    2021-05-12T08:40:47.653+00:00

    You can add a loop to your code, or DispatcherTimer to execute the LongTime. I will show you my demo with use a loop, if you want to use DispatcherTimer, you can refer to the answer.

    The Xaml code :

     <Window.DataContext>  
            <local:ViewModel></local:ViewModel>  
        </Window.DataContext>  
        <Grid>  
            <TextBox Text="{Binding Val,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="200" Height="40" Background="Azure"/>  
        </Grid>  
    

    The C# code is:

    public class ViewModel : NotifyObject  
        {  
      
            public ViewModel()  
            {  
                Val = 0;  
                Thread thread = new Thread(LongTime);  
                thread.IsBackground = true;  
                thread.Start();  
            }  
      
            private int _Val;  
            public int Val  
            {  
                get  
                {  
                    return _Val;  
                }  
                set  
                {  
                    _Val = value;  
                    OnPropertyChanged("Val");  
                }  
            }  
      
            public void LongTime()  
            {  
                int j = 0;  
      
                for (int i = 0; i < 10000000; i++)  
                {  
                    while (j != 10000000)  
                    {  
                        if (i % 1000 == 0)  
                        {  
                            Val++;  
                        }  
                        j++;  
                    }  
                }  
            }  
        }  
    

    The result pictire is:
    95961-3.gif


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


1 additional answer

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,056 Reputation points
    2021-05-13T07:21:34.937+00:00

    Hi,
    you can use Task.Factory, see following code:

    using System.ComponentModel;  
    using System.Runtime.CompilerServices;  
    using System.Threading.Tasks;  
    using System.Windows;  
     
    namespace WpfApp054  
    {  
      public class myClass : FrameworkElement, INotifyPropertyChanged  
      {  
        public myClass() => Task.Factory.StartNew(() => LongTime());  
      
        private int _val;  
        public int Val { get => this._val; set { this._val = value; OnPropertyChanged(); } }  
      
        public void LongTime()  
        {  
          for (int i = 0; i < 10000000; i++)  
          {  
            if (i % 1000 == 0) Val++;  
            for (int k = 0; k < 10000; k++) { } // simulate working   
          }  
        }  
      
        public event PropertyChangedEventHandler PropertyChanged;  
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));  
      }  
    }  
    

    And XAML:

    <Window x:Class="WpfApp1.Window054"  
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
            xmlns:local="clr-namespace:WpfApp054"  
            mc:Ignorable="d"  
            Title="Long running method" Height="450" Width="800">  
      <StackPanel>  
        <local:myClass x:Name="myClass"/>  
        <TextBox Text="insert text to check non-blocking UI" />  
        <TextBox Text="{Binding ElementName=myClass, Path=Val}" />  
      </StackPanel>  
    </Window>  
    

    Result:

    96169-x.gif