I did a little WPF window with a button and a textBox.
When I click on the button, there is some stuff, then I add some lines to my TextBox.
I often did this kind of apps with Winform and when I did them, the UI refreshed each time the textbox was updated, but not in my WPF application.
So I read about and did binding and used the INotifyPropertyChanged.
public partial class MainWindow : MetroWindow, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
private string myValue;
public string MyValue
{
get { return myValue; }
set
{
myValue = value;
RaisePropertyChanged("MyValue");
}
}
private void RaisePropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
public event PropertyChangedEventHandler PropertyChanged;
//
//.......
//
}
Then my XAML :
<TextBox x:Name="TxtBox_result" Text="{Binding Path=MyValue}" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalScrollBarVisibility="Auto" AcceptsReturn="True" Margin="30,332,0,0" VerticalAlignment="Top" Width="868" Height="285" TextChanged="TxtBox_result_TextChanged" />
I know there is probably cleaner code to do with MVVM approach but I don't know MVVM but would like to try first to have a simple method to refresh my UI. It's a shame because it was easier in Win32.
Here is the code executed when i click on the button, i update the MyValue on these code but the TextBox only show value when the treatment is over :
private void GenererBases (string DirectoryStd, string DirectorySur)
{
int cpt = 0;
bool bSignatureBaseFound = false;
bool bFirst = true;
string strDirectoryOut = string.Empty;
var files = Directory.GetFiles(DirectorySur, "*.*", SearchOption.TopDirectoryOnly)
.Where(s => s.EndsWith(".txt") || s.EndsWith(".dat"));
MyValue = " ";
MyValue = " > Recherche des fichiers ...." Environment.NewLine;
foreach (string fileName in files)
{
string line = string.Empty;
string FileNameStandard = string.Empty;
bSignatureBaseFound = false;
MyValue = MyValue Environment.NewLine " > Extraction de la signature du fichier base pour : " System.IO.Path.GetFileName(fileName);
System.IO.StreamReader file = new System.IO.StreamReader(fileName);
while ((line = file.ReadLine()) != null)
{
if (line.Contains("SetModuleInfo('$Id:"))
{
bSignatureBaseFound = true;
int posDebFichier = line.IndexOf("'$Id:") 6;
int posFinFichier = line.IndexOf(" ", (line.IndexOf("'$Id:") 6));
FileNameStandard = line.Substring(posDebFichier, posFinFichier-posDebFichier);
if (File.Exists(DirectoryStd @"\" FileNameStandard))
{
MyValue = MyValue Environment.NewLine " > Fichier base : " FileNameStandard " localisé ! > Copie vers le dossier de destination !";
if (bFirst)
{
strDirectoryOut = DirectorySur @"\Generated_bases_" DateTime.Now.ToString("yyyyMMddHHmm");
Directory.CreateDirectory(strDirectoryOut);
bFirst = false;
}
cpt ;
if (File.Exists(strDirectoryOut @"\" System.IO.Path.GetFileNameWithoutExtension(FileNameStandard) "_base" System.IO.Path.GetExtension(FileNameStandard)))
{
File.Delete(strDirectoryOut @"\" System.IO.Path.GetFileNameWithoutExtension(FileNameStandard) "_base" System.IO.Path.GetExtension(FileNameStandard));
}
File.Copy(DirectoryStd @"\" FileNameStandard, strDirectoryOut @"\" System.IO.Path.GetFileNameWithoutExtension(FileNameStandard) "_base" System.IO.Path.GetExtension(FileNameStandard),true);
File.SetAttributes(strDirectoryOut @"\" System.IO.Path.GetFileNameWithoutExtension(FileNameStandard) "_base" System.IO.Path.GetExtension(FileNameStandard), File.GetAttributes(strDirectoryOut @"\" System.IO.Path.GetFileNameWithoutExtension(FileNameStandard) "_base" System.IO.Path.GetExtension(FileNameStandard)) | FileAttributes.Hidden);
}
else
{
MyValue = MyValue Environment.NewLine "!!! WARNING!!" Environment.NewLine "!!! Fichier base non localisé : " FileNameStandard Environment.NewLine;
}
break;
}
}
file.Close();
if (bSignatureBaseFound==false)
{
MyValue = MyValue Environment.NewLine "!!! WARNING!!" Environment.NewLine "!!! Aucune signature de base localisée pour : " fileName Environment.NewLine;
}
}
MyValue = MyValue Environment.NewLine "***************************" Environment.NewLine "***************************" Environment.NewLine " >> Fin du traitement !" cpt " fichiers bases générés pour " files.Count() " sources surchargés !" Environment.NewLine ">> Fichiers bases copiés dans le dossier :" strDirectoryOut Environment.NewLine;
}
Thanks a lot
CodePudding user response:
A simple example.
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls.Primitives;
namespace Core2022.SO.WalterFabioSimoni
{
public partial class InpcWindow : Window, INotifyPropertyChanged
{
protected bool Set<T>(ref T propertyField, T newValue, [CallerMemberName] string? propertyName = null)
{
if (string.IsNullOrWhiteSpace(propertyName))
throw new ArgumentNullException(nameof(propertyName));
bool notEquals = !Equals(propertyField, newValue);
if (notEquals)
{
propertyField = newValue;
RaisePropertyChanged(propertyName);
}
return notEquals;
}
protected void RaisePropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName ?? string.Empty));
}
public event PropertyChangedEventHandler? PropertyChanged;
}
public partial class AsyncUpdateWindow : InpcWindow
{
public AsyncUpdateWindow()
{
InitializeComponent();
}
private string _myValue = string.Empty;
public string MyValue
{
get => _myValue;
set => Set(ref _myValue, value ?? string.Empty);
}
private static readonly Random random= new Random();
private async void OnRestartAsync(object sender, RoutedEventArgs e)
{
UIElement button = (UIElement)sender;
button.SetCurrentValue(IsEnabledProperty, false);
for (int i = 0; i < 10; i )
{
MyValue = random.Next(int.MinValue, int.MaxValue).ToString();
await Task.Delay(500);
}
button.InvalidateProperty(IsEnabledProperty);
}
}
}
<local:InpcWindow x:Class="Core2022.SO.WalterFabioSimoni.AsyncUpdateWindow"
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:Core2022.SO.WalterFabioSimoni"
mc:Ignorable="d"
Title="AsyncUpdateWindow" Height="300" Width="400"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<UniformGrid Columns="1">
<Viewbox>
<TextBlock Text="{Binding MyValue}" Margin="10"/>
</Viewbox>
<Button Content="Restart" Click="OnRestartAsync"/>
</UniformGrid>
</local:InpcWindow>
There are no calls to UI elements in your method code - this is very good. For your code, you just need to add the following method:
private async void GenererBasesAsync(string DirectoryStd, string DirectorySur)
=> await Task.Run(() => GenererBases(DirectoryStd, DirectorySur));
In the clicker, call this async method.