Сделал на основе вашего кода. Вообще нужно это всё писать немного иначе. Передавать ссылку в классы с алгоритмами на контролы - это очень плохая идея и сразу забудьте про такой подход.
В этом примере если два раза нажать на пункт меню, то запустится два цикла в поток(е/ах) из пула потоков. Это уже сами обработаете.
В данном примере
Analyzer - это отдельная сущность, которая умеет уведомлять о каких-то своих внутренних событиях внешний мир посредством сигналов. Событие и есть тот самый сигнал, а обработать его сможет любое кол-во подписчиков. Событие можно воспринимать, как пины на плате Raspberry Pi, если к нему что-то подсоединить, то можно как-то реагировать на сигнал от пина, тут тоже самое.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ProgressBarExample
{
internal class Analyzer
{
private readonly SynchronizationContext _synchronizationContext;
public Analyzer()
{
// Если экземпляр класса будет создан в UI потоке,
// то здесь будет контекст синхронизации UI потока, иначе пула потоков
_synchronizationContext = SynchronizationContext.Current ?? new SynchronizationContext();
}
public event EventHandler<AnalyzerEventArgs> ProgressChanged;
public async Task<Data> LoadDataInDB()
{
var result = await Task.Run(async () =>
{
for (int i = 0; i < 100; i++)
{
await Task.Delay(250);
OnProgressChanged(new AnalyzerEventArgs("line " + (i + 1), 100));
}
return new Data() { Text = "Данные " };
});
return result;
}
private void OnProgressChanged(AnalyzerEventArgs args)
{
// Перенаправляем выполнение в UI поток не ожидая пока отработает метод обработчик события.
_synchronizationContext.Post(state =>
{
ProgressChanged?.Invoke(this, (AnalyzerEventArgs)state);
}, args); // args передаётся в переменную state (грубо говоря)
}
}
}
namespace ProgressBarExample
{
public class AnalyzerEventArgs
{
public int MaxLines { get; }
public string CurrentLine { get; }
public AnalyzerEventArgs(string currentLine, int maxLines)
{
CurrentLine = currentLine;
MaxLines = maxLines;
}
}
}
namespace ProgressBarExample
{
public class Data
{
public string Text { get; set; }
}
}
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;
namespace ProgressBarExample
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
private readonly Analyzer _analyzer;
private readonly Style _normalBarStyle;
private readonly Style _loadBarStyle;
private readonly Style _errorBarStyle;
private string _maxLines;
private string _currentLine;
public string MaxLines
{
get { return _maxLines; }
set
{
_maxLines = value;
OnPropertyChanged();
}
}
public string CurrentLine
{
get { return _currentLine; }
set
{
_currentLine = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
public MainWindow()
{
InitializeComponent();
_normalBarStyle = FindResource("NormalStatusBar") as Style;
_loadBarStyle = FindResource("LoadDataStatusBar") as Style;
_errorBarStyle = FindResource("ErrorStatusBar") as Style;
_statusBar.Style = _normalBarStyle;
_analyzer = new Analyzer();
_analyzer.ProgressChanged += OnAnalyzerProgressChanged;
}
private void OnAnalyzerProgressChanged(object sender, AnalyzerEventArgs args)
{
// Передавать каждый раз одно и тоже бессмысленно, сделаете сами как нужно
MaxLines = args.MaxLines.ToString();
CurrentLine = args.CurrentLine;
}
private async void LoadDataToDB_Click(object sender, RoutedEventArgs e)
{
_statusBar.Style = _loadBarStyle;
Mouse.OverrideCursor = Cursors.Wait;
try
{
var data = await _analyzer.LoadDataInDB();
MessageBox.Show(data.Text);
}
finally
{
Mouse.OverrideCursor = Cursors.Arrow;
_statusBar.Style = _normalBarStyle;
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
<Window
x:Class="ProgressBarExample.MainWindow"
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:local="clr-namespace:ProgressBarExample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
mc:Ignorable="d">
<Window.Resources>
<Style x:Key="NormalStatusBar" TargetType="DockPanel">
<Setter Property="Background" Value="#FF007ACC" />
</Style>
<Style x:Key="LoadDataStatusBar" TargetType="DockPanel">
<Setter Property="Background" Value="#9333FF" />
</Style>
<Style x:Key="ErrorStatusBar" TargetType="DockPanel">
<Setter Property="Background" Value="#eb4034" />
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Menu VerticalAlignment="Top">
<MenuItem Header="File">
<MenuItem
x:Name="LoadDataToDB"
Click="LoadDataToDB_Click"
Header="LoadDataToDB" />
</MenuItem>
</Menu>
<DockPanel
x:Name="_statusBar"
Grid.Row="1"
Style="{StaticResource LoadDataStatusBar}">
<!-- Style меняться во время выполнения LoadDataInDB() -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Margin="10,0,0,0"
Foreground="White"
Text="Статус данных" />
<DockPanel Grid.Column="1" HorizontalAlignment="Right">
<TextBlock
Margin="0,0,5,0"
Foreground="White"
Text="{Binding CurrentLine}" />
<!-- должно меняться во время выполнения LoadDataInDB() -->
<TextBlock
Margin="0,0,5,0"
Foreground="White"
Text="/" />
<TextBlock
Margin="0,0,10,0"
Foreground="White"
Text="{Binding MaxLines}" />
</DockPanel>
</Grid>
</DockPanel>
</Grid>
</Window>