I have a simple progress bar and status message textblock bound to a view model that should iterate in a foreach statement. it works fine in testing when a put a MessageBox in the foreach but if I take out the MessageBox the only status that's being captured is the last iteration and I can't determine what I need to do to correct that.
ViewModel -
public class ExampleViewModel : INotifyPropertyChanged
{
public RelayCommand<IList> Submit { get; }
private KeyValuePair<Model, string[]> _selectedItem;
public KeyValuePair<Model, string[]> SelectedItem
{
get => _selectedItem;
set
{
_selectedItem = value;
RaisePropertyChanged(nameof(SelectedItem));
}
}
public ExampleViewModel()
{
Submit = new RelayCommand<IList>(ExecuteSubmit);
}
private void ExecuteSubmit(IList selectedItems)
{
string[] examples = new string[] {"a", "b", "c"};
double percentAge = 100/examples.Count;
if (examples.Count > 0)
{
foreach (var ex in examples)
{
CurrentProgress = CurrentProgress percentAge;
MessageBox.Show("Step " ex); // Status and Progress Bar update when this isn't commented out
// Thread.Sleep(1000);
StatusMessages = "Option " ex;
}
}
return;
}
#region Status Fields
private string _statusMessages;
public string StatusMessages
{
get => _statusMessages;
set
{
if (_statusMessages != value)
{
_statusMessages = value;
RaisePropertyChanged(nameof(StatusMessages));
}
}
}
private double _currentProgress;
public double CurrentProgress
{
get => _currentProgress;
set
{
if (_currentProgress != value)
{
_currentProgress = value;
RaisePropertyChanged(nameof(CurrentProgress));
}
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(propertyName));
}
}
}
XAML -
<ProgressBar Value="{Binding CurrentProgress, Mode=OneWay}"
Margin="5,5" Height="10" Width="240" HorizontalAlignment="Left"/>
<TextBlock Margin="5,5" Height="15" Width="240" TextWrapping="Wrap"
Foreground="Red"
Text="{Binding StatusMessages}"></TextBlock>
CodePudding user response:
Calling Thread.Sleep(1000);
on UI thread is wrong.. It freezes the UI and once the freeze ends it will start a new freeze so it could not even update any of the UI elements that are bound with the properties.. You can use DispatcherTimer
instead
Replace
foreach (var ex in examples)
{
CurrentProgress = CurrentProgress percentAge;
MessageBox.Show("Step " ex); // Status and Progress Bar update when this isn't commented out
// Thread.Sleep(1000);
StatusMessages = "Option " ex;
}
With
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(1)
};
int ticksCount = 0;
var ticksLimit = examples.Count;
timer.Tick = (_, _) =>
{
ticksCount ;
if (ticksCount > ticksLimit)
timer.Stop();
else
{
var ex = examples[ticksCount - 1];
CurrentProgress = CurrentProgress percentAge;
StatusMessages = "Option " ex;
}
};
timer.Start();