我正在开发WPF应用程序。我在我的应用程序中使用MahApps Metro控件和主题。当其他进程正在运行时,我想显示一个Loading指示器。此过程还将更新UI。问题是加载指示器不显示
<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;
}
}
加载属性类似于
private bool _isLoading = false;
public bool IsLoading
{
get => _isLoading;
set
{
if (_isLoading != value)
{
_isLoading = value;
OnPropertyChanged(nameof(IsLoading));
}
}
}
在Click事件按钮上,我想执行多个SQL查询,并根据结果创建多个选项卡。
谁能帮助我为什么ProgressRing是不可见的?
我也试过下面的代码,它工作正常,
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;
}
}
在不同的Task中执行数据库访问是可以的。但是您不应该像以前那样使用分派器调用方法。当您使用调度程序时,数据库访问是在UI线程下完成的,它阻塞了UI更新。在任务运行时,您可以使用调度程序调用来更新与UI相关的属性。通过这样做,您将不会用冗长的SQL调用阻塞UI,并且仍然能够更新UI。IsLoading属性实际上立即被设置为false !顺序如下:任务开始,它向调度程序发送一个要执行的动作,任务结束,并将IsLoading设置为false。之后,SQL部分在UI线程下使用您之前设置的操作执行。
我包含了一个稍微修改过的工作代码。
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ProgressBar Grid.Row="0" IsIndeterminate="{Binding IsLoading}" />
<TabControl Grid.Row="1" Name="outputTab"/>
<Button Grid.Row="2" Click="Button_Click" Width="100">Load</Button>
</Grid>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ExecutionWindowViewModel();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
if (DataContext is ExecutionWindowViewModel viewModel)
{
if (outputTab.Items.Count > 0)
{
outputTab.Items.Clear();
}
var selectedDatabases = viewModel.Databases;
viewModel.IsLoading = true;
await Task.Run(() =>
{
foreach (var database in selectedDatabases)
{
viewModel.SQLQueryExecution();
this.Dispatcher.BeginInvoke((Action)(() => {
DataGrid sqlOutput = new DataGrid();
sqlOutput.AutoGenerateColumns = true;
sqlOutput.IsReadOnly = true;
TabItem tabItem = new TabItem();
tabItem.Header = database.ToString();
tabItem.Content = sqlOutput;
outputTab.Items.Add(tabItem); }));
}
this.Dispatcher.BeginInvoke((Action)(() => { viewModel.IsLoading = false; }));
});
}
}
}
public class ExecutionWindowViewModel: INotifyPropertyChanged
{
public ExecutionWindowViewModel()
{
Databases = new List<string>();
Databases.Add("DB1");
Databases.Add("DB2");
Databases.Add("DB3");
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged( String propertyName )
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
bool _isLoading;
public bool IsLoading
{
get { return _isLoading; }
set {
_isLoading = value;
NotifyPropertyChanged(nameof(IsLoading));
}
}
public List<string> Databases { get; set; }
public void SQLQueryExecution()
{
Thread.Sleep(3000);
}
}
作为注释,我正在为后面的代码添加另一种风格。但我发布的第一个是有效的,是合法的。我也同意这不是关于VM的最佳实践,但这不是这里的问题。
private async void Button_Click(object sender, RoutedEventArgs e)
{
if (DataContext is ExecutionWindowViewModel viewModel)
{
if (outputTab.Items.Count > 0)
{
outputTab.Items.Clear();
}
var selectedDatabases = viewModel.Databases;
viewModel.IsLoading = true;
await Task.Run(() =>
{
foreach (var database in selectedDatabases)
{
viewModel.SQLQueryExecution();
this.Dispatcher.Invoke(() => {
DataGrid sqlOutput = new DataGrid();
sqlOutput.AutoGenerateColumns = true;
sqlOutput.IsReadOnly = true;
TabItem tabItem = new TabItem();
tabItem.Header = database.ToString();
tabItem.Content = sqlOutput;
outputTab.Items.Add(tabItem); });
}
});
viewModel.IsLoading = false;
}
}