问题
Windows 10 Mobile上的文件管理器有这样一个进度指示器,它是一个模态框,不带任何按钮,只有进度条和文本:
解决方法
今天我琢磨了很久,绕了一些弯路,发现其实要做一个这样的模态进度指示器很简单。只要用ContentDialog就行。
平时我们用ContentDialog有些思维定势,就觉得这个对话框一定要提供按钮给用户操作。其实它是可以不设置任何按钮的,这样就有了初步的雏形:
XAML
<ContentDialog x:Name="ModalProgressDig">
<ContentControl.Content>
<StackPanel Margin="0,10,0,10">
<ProgressBar IsIndeterminate="True" />
<TextBlock Text="坐和放宽" TextAlignment="Center" Margin="0,10,0,0" />
</StackPanel>
</ContentControl.Content>
</ContentDialog>
<Button x:Name="BtnSitAndRelax" Content="坐和放宽" Click="BtnSitAndRelax_OnClick" />
C#
private async void BtnSitAndRelax_OnClick(object sender, RoutedEventArgs e)
{
// show progress
await ModalProgressDig.ShowAsync();
}
之后有2个问题要解决。
1. 如何在操作完成后关闭这个对话框
以前是通过用户点击按钮后主动关闭对话框的,就像这样
var result = await ModalProgressDig.ShowAsync();
if(result == ...){ // 这时候对话框已经被用户关闭了 }
现在没有了按钮,我们要从代码里关闭这个对话框。
关闭对话框的代码是:
ModalProgressDig.Hide();
但是不能这样做:
private async void BtnSitAndRelax_OnClick(object sender, RoutedEventArgs e)
{
// show progress
await ModalProgressDig.ShowAsync();
// do some logic
await Task.Delay(5000);
// hide progress
ModalProgressDig.Hide();
}
因为你会卡在第一个await上。得等第一个await结束(即用户主动关闭对话框)才会执行后面的逻辑。
所以要用一个trick:
private async void BtnSitAndRelax_OnClick(object sender, RoutedEventArgs e)
{
// show progress
var progressTask = ModalProgressDig.ShowAsync();
// do some logic
await Task.Delay(5000);
// hide progress
progressTask.Cancel();
ModalProgressDig.Hide();
}
现在操作完成后就会自动关闭对话框了。但是我不知道这样写代码会不会有什么问题。
2. 对话框的样式修改
以前我们要修改控件的默认样式可以在Blend里右键拷出默认模板编辑,结果这个ContentDialog居然拷不出来。所以要在MSDN上找一个默认模板来改:
https://msdn.microsoft.com/en-us/library/windows/apps/mt299120.aspx
我们主要改的就是对话框的高度。从上面的截图对比发现我们自己做的对话框高度明显太高了。
所以,在这个默认模板里找到:
<Setter Property="MaxHeight" Value="{ThemeResource ContentDialogMaxHeight}" />
<Setter Property="MinHeight" Value="{ThemeResource ContentDialogMinHeight}" />
和Border上的
MaxHeight="{TemplateBinding MaxHeight}"
MinHeight="{TemplateBinding MinHeight}"
把这对代码删了就好。
修改后的样式如下(我个人喜好,把Border改成2px了,这个改不改无所谓):
<Style TargetType="ContentDialog" x:Key="SitAndRelaxDialogStyle">
<Setter Property="Foreground" Value="{ThemeResource SystemControlPageTextBaseHighBrush}" />
<Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="MaxWidth" Value="{ThemeResource ContentDialogMaxWidth}" />
<Setter Property="MinWidth" Value="{ThemeResource ContentDialogMinWidth}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentDialog">
<Border x:Name="Container">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border x:Name="BackgroundElement"
Background="{TemplateBinding Background}"
FlowDirection="{TemplateBinding FlowDirection}"
BorderThickness="2"
BorderBrush="{ThemeResource SystemControlForegroundAccentBrush}"
MaxWidth="{TemplateBinding MaxWidth}"
MinWidth="{TemplateBinding MinWidth}"
>
<Grid x:Name="DialogSpace" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer x:Name="ContentScrollViewer"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Disabled"
ZoomMode="Disabled"
Margin="{ThemeResource ContentDialogContentScrollViewerMargin}"
IsTabStop="False">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl x:Name="Title"
Margin="{ThemeResource ContentDialogTitleMargin}"
Content="{TemplateBinding Title}"
ContentTemplate="{TemplateBinding TitleTemplate}"
FontSize="20"
FontFamily="XamlAutoFontFamily"
FontWeight="Normal"
Foreground="{TemplateBinding Foreground}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
IsTabStop="False"
MaxHeight="{ThemeResource ContentDialogTitleMaxHeight}" >
<ContentControl.Template>
<ControlTemplate TargetType="ContentControl">
<ContentPresenter
Content="{TemplateBinding Content}"
MaxLines="2"
TextWrapping="Wrap"
ContentTemplate="{TemplateBinding ContentTemplate}"
Margin="{TemplateBinding Padding}"
ContentTransitions="{TemplateBinding ContentTransitions}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</ControlTemplate>
</ContentControl.Template>
</ContentControl>
<ContentPresenter x:Name="Content"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
FontSize="{ThemeResource ControlContentThemeFontSize}"
FontFamily="{ThemeResource ContentControlThemeFontFamily}"
Margin="{ThemeResource ContentDialogContentMargin}"
Foreground="{TemplateBinding Foreground}"
Grid.Row="1"
TextWrapping="Wrap" />
</Grid>
</ScrollViewer>
<Grid x:Name="CommandSpace" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border x:Name="Button1Host"
Margin="{ThemeResource ContentDialogButton1HostMargin}"
MinWidth="{ThemeResource ContentDialogButtonMinWidth}"
MaxWidth="{ThemeResource ContentDialogButtonMaxWidth}"
Height="{ThemeResource ContentDialogButtonHeight}"
HorizontalAlignment="Stretch" />
<Border x:Name="Button2Host"
Margin="{ThemeResource ContentDialogButton2HostMargin}"
MinWidth="{ThemeResource ContentDialogButtonMinWidth}"
MaxWidth="{ThemeResource ContentDialogButtonMaxWidth}"
Height="{ThemeResource ContentDialogButtonHeight}"
Grid.Column="1"
HorizontalAlignment="Stretch" />
</Grid>
</Grid>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
然后在我们的对话框上引用这个样式:
<ContentDialog x:Name="ModalProgressDig" Style="{StaticResource SitAndRelaxDialogStyle}">
大功告成: