I am working on WPF application. I am using MahApps Metro controls and theme in my application. I want to show a Loading indicator when some other process is running. This process will also update the UI. The problem is loading Indicator does not display.
<mah:ProgressRing x:Name="loadingIndicator" Grid.RowSpan="2"
Foreground="{DynamicResource AccentColorBrush}"
IsActive="{Binding IsLoading}" />
private async void ExecuteButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (DataContext is ExecutionWindowViewModel viewModel)
{
if (outputTab.Items.Count > 0)
{
outputTab.Items.Clear();
}
var selectedDatabases = viewModel.Databases.Where(x => x.IsSelected == true).ToList();
viewModel.IsLoading = true;
await Task.Run(() =>
{
this.Dispatcher.Invoke(new Action(() =>
{
foreach (var database in selectedDatabases)
{
TabItem tabItem = new TabItem();
tabItem.Header = database.DBShortName;
DataGrid sqlOutput = new DataGrid();
sqlOutput.AutoGenerateColumns = true;
sqlOutput.IsReadOnly = true;
var test = viewModel.SQLQueryExecution(database.ConnectionString);
sqlOutput.ItemsSource = viewModel.SQLQueryExecution(database.ConnectionString).AsDataView();
tabItem.Content = sqlOutput;
outputTab.Items.Add(tabItem);
}
}));
});
viewModel.IsLoading = false;
}
}
loading property is like
private bool _isLoading = false;
public bool IsLoading
{
get => _isLoading;
set
{
if (_isLoading != value)
{
_isLoading = value;
OnPropertyChanged(nameof(IsLoading));
}
}
}
On the button Click event, I want to execute multiple SQL queries, and based on the result I want to create multiple tabs.
Can anyone help me why ProgressRing is not visible?
I have also tried the below code and it is working correctly,
private async void ExecuteButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (DataContext is ExecutionWindowViewModel viewModel)
{
if (outputTab.Items.Count > 0)
{
outputTab.Items.Clear();
}
var selectedDatabases = viewModel.Databases.Where(x => x.IsSelected == true).ToList();
viewModel.IsLoading = true;
await Task.Delay(10000);
viewModel.IsLoading = false;
}
}
It is OK to execute the data base access in a different Task as you did. But you should not use the dispatcher invoke method the way you did it. When you use the dispatcher the data base access is done under the UI thread and it blocks the UI update. While the task is running , you can use the dispatcher invoke for the update of UI related properties only. By doing so you will not block the UI with lengthy SQL calls and still be able to update the UI. The IsLoading property is actually set to false immediately! The Sequence is as following: The task is starting, it sends to the dispatcher an action to be execute and the task is terminating and setting the IsLoading to false. After that the SQL part is executed under the UI thread with the action you set before.
I include a working code that is slightly modified.
As of the comments I am adding another flavor for the code behind. But also the first one I posted is working and is legitimate. I also agree that this is not the best practice regarding the VM but this is not the issue here.