我正在开发用于管理森林目录的桌面应用程序。启动应用程序时,必须从MySql数据库中显示某些数据,这会减慢应用程序的启动速度,因此我想显示一个对话框,其中显示动画gif,直到数据加载完成。 问题是应用程序冻结,并且直到数据加载完成才显示对话框。我搜索了其他帖子,但找不到解决方案。感谢您的帮助。
这是我的MainWindow XAML:
<mui:ModernWindow x:Class="ModernUINavigationApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
Title="Media Copy Manager" IsTitleVisible="True"
WindowStartupLocation="CenterScreen"
ContentSource="/gui/Pages/PHome.xaml" WindowState="Maximized">
<mui:ModernWindow.MenuLinkGroups>
( ...)
</mui:ModernWindow.MenuLinkGroups>
这是我的PHome.xaml页面:
<UserControl x:Class="MCP.gui.Pages.PHome"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
mc:Ignorable="d">
<Grid Style="{StaticResource ContentRoot}" Margin="0 0 0 0" Name="_contentRoot">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TabControl Grid.Row="0" Grid.Column="0" Name="_TAB" TabStripPlacement="Left"/>
</Grid>
这是我的Home.cs代码:
{
public PHome()
{
InitializeComponent();
this.Loaded += ContentLoaded;
}
private void ContentLoaded(object sender, RoutedEventArgs e)
{
Thread t = new Thread(() =>
{
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
(Action)(() =>
{
new LoadingDialog().Show();
}));
});
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
Task.Run(() =>
{
_TAB.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
(Action)(() =>
{
Populate_Tab(_TAB);
}));
});
}
private async void Populate_Tab(TabControl tabControl)
{
tabControl.Items.Clear();
tabControl.ClipToBounds = true;
List<categoria> ListaCategorias = await DBManager.CategoriasRepo.ListAsync;
foreach (categoria categ in ListaCategorias)
{
TabItem tabitem = new TabItem();
tabitem.Header = categ.categoria1;
Thread.Sleep(1000); //Do some long execution process
tabControl.Items.Add(tabitem);
}
}
}
这是我的LoadingDialog XAML:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
mc:Ignorable="d" d:DesignWidth="300"
Title="ModernDialog" Background="{x:Null}" Height="197.368">
<StackPanel>
<TextBlock>LOADING</TextBlock>
<mui:ModernProgressRing IsActive="True" Name="_LoaderGif" Width="100" Height="100" Style="{StaticResource ThreeBounceProgressRingStyle}" Margin="47,43,68,65" />
</StackPanel>
</mui:ModernDialog>
答案 0 :(得分:0)
您需要更好地了解所使用的方法,尤其是用来尝试将其移动到其他线程上的方法。在我解释之前,请记住以下几点:
您似乎不了解的是Dispatcher.Invoke
。
就像Task.Run
将代码执行移至新线程一样,Dispatcher.Invoke
将代码执行移至返回UI主题。
让我们采用您的方法ContentLoaded
。在您的代码中,您尝试同时使用Thread
和Task
类将某些代码移到单独的线程上。但是,您从这些新线程中所做的全部工作就是立即调用Dispatcher.Invoke
,它会在UI线程上执行代码。从理论上讲,这实际上会使您的应用程序变慢,因为它浪费时间创建新线程并无缘无故地在它们之间跳转。
您需要做的是Populate_Tab
,并将其分成两种(或多种)不同的方法:一种会影响UI,而另一种不会。
像tabControl.Items.Clear
和tabitem.Header = categ.categoria1
这样的调用必须在UI线程上进行,因为它们直接引用UI元素,但是您长期运行的操作(例如访问数据库)可以并且应该移至另一个线程。
顺序应为:
Task
和async
一起使用await
,因为这是当前的最佳做法。await
将所需数据返回到UI线程,并根据需要更新UI。