Windows App开发之常用控件与应用栏

控件的属性、事件与样式资源

如何添加控件

添加控件的方式有多种,大家更喜欢下面哪一种呢?

1)使用诸如Blend for Visual Studio或Microsoft Visual Studio XAML设计器的设计工具。
2)在Visual Studio XAML编辑器中将控件添加到XAML代码中。
3)在代码中添加控件。 注意:当应用运行时会看到你在代码中添加的控件,但在 Visual Studio XAML 设计器中看不到。

前面我们通过在工具箱拖住控件以及直接在写XAML代码来设置控件,在教程的后面,我们会看到在C#后台代码中添加控件。Blend我们暂时还没有用到,不过其在绘制图形和动画上可谓非常强大和优秀。

设置控件的属性

控件的属性相比大家都已经会用了,一来可以直接在XAML中添加属性,二来可以在属性视图中添加和修改属性。

这里写图片描述

为控件添加事件

如果要添加和修改事件呢,同样在属性视图中,点击右上角的闪电图标即可。如果要添加Click事件,那么在Click的输入框中输入好事件名称后直接按Enter即可。此时VS就会自动跳转到C#后台代码中,第一个参数sender是对处理程序所附加的对象的应用,第二参数是事件数据,它通常在签名中显示为e参数。

private void btnSetStyle_Click(object sender, RoutedEventArgs e)
{
    Button b = (Button)sender;
    b.Height = 400;
    b.Width = 320;
}

上面的这段代码这会将所点击的Button的高设置为400,宽设置为320;除了这种方式外,也可以按如下操作,其中btnSetStyle是当前Button的名字:

private void btnSetStyle_Click(object sender, RoutedEventArgs e)
{
    btnSetStyle.Height = 400;
    btnSetStyle.Width = 320;
}

除此之外,我们也可以不在XAML中定义Click事件,按照如下操作也可以达到相同的效果,它会将两个事件相互关联。

public MainPage()
{
     this.InitializeComponent();

     btnSetStyle.Click += new RoutedEventHandler(btnSetStyle_Click);
}

private void btnSetStyle_Click(object sender, RoutedEventArgs e)
{
    btnSetStyle.Height = 400;
    btnSetStyle.Width = 320;
}

为控件设置样式资源

即便没有添加过资源,也不清楚什么是样式,没关系,想必大家都玩过2048吧。游戏中有许多方格,那这些方格的样式会不会一个个去定义呢,当然不是,可以直接用样式资源来定位到所有的Button。

以下是一个基本样式,

<Page.Resources>
   <Style TargetType="Button">
      <Setter Property="FontWeight" Value="Bold"/>
      <Setter Property="FontSize" Value="40"/>
      <Setter Property="HorizontalAlignment" Value="Center"></Setter>
      <Setter Property="VerticalAlignment" Value="Center"></Setter>
      <Setter Property="Background" Value="Gray"></Setter>
      <Setter Property="Width" Value="100"></Setter>
      <Setter Property="Height" Value="100"></Setter>
      <Setter Property="Template">
          <Setter.Value>
              <ControlTemplate TargetType="Button">
                  <Grid x:Name="Grid" Background="Transparent">
                      <Border x:Name="Border" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Background="{TemplateBinding Background}" >
                          <ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="Center"  VerticalAlignment="Center"/>
                       </Border>
                   </Grid>
               </ControlTemplate>
           </Setter.Value>
       </Setter>
    </Style>
</Page.Resources>

但是这里也有一个问题,如果我们有10个Button控件,却只想其中8个用到这些定义,另外2个想用另一种控件,那该怎么办呢?

将样式定义为资源,其实是有2中方式的。

一种就是直接用Style的TargetType属性来定义到所有的目标控件。

另一种则除了用TargetType属性外,还可以用x:key属性,然后再具体的控件中庸显式的关键字StaticResource来设置具体的Style属性。

<Page.Resources>     
     <Style TargetType="Button">              
         <Setter Property="FontStyle" Value="Oblique" />
         <Setter Property="FontSize" Value="20" />
         <Setter Property="BorderBrush" Value="Green" />
         <Setter Property="BorderThickness" Value="5" />
         <Setter Property="Foreground" Value="Orange" />
         <Setter Property="Height" Value="80"/>
         <Setter Property="Width" Value="160"/>
     </Style>

     <Style x:Key="OtherStyle" TargetType="Button">
         <Setter Property="FontStyle" Value="Italic" />
         <Setter Property="FontSize" Value="16" />
         <Setter Property="Foreground" Value="Lavender" />
         <Setter Property="Height" Value="160"/>
         <Setter Property="Width" Value="320"/>
         <Setter Property="Opacity" Value="0.2"/>
     </Style>                                                            
</Page.Resources>

具体效果见下图,其中Opacity属性为透明度。

这里写图片描述

大家都知道类可以继承,样式也是可以继承的。

部分控件介绍

通过前面的学习,已经见过一些控件了,现在起将逐步见到更多控件。但由于控件太多,教程中无法一一介绍,请自行举一反三。教程内容也将不断更新。

Button

前面最常用的控件就是Button了,Button还有一个有意思的属性,当把鼠标指针放在Button上时,就会在Button的头顶冒出一串文本。

<Button ToolTipService.ToolTip="Go to www.blog.youkuaiyun.com/nomasp" Margin="692,458,0,230"/>

Button有一个很有意思的属性。

<Button Content="摩天轮" Margin="134,363,0,367">               
    <ToolTipService.ToolTip>
        <Image MaxHeight="80" MaxWidth="100" Source="Assets/343219.jpg"/>       
    </ToolTipService.ToolTip>     
</Button>

只要把鼠标放到Button上面就会显示出这张图片了,也叫做帮助提示吧。其实更简单的方法是下面这种。它显示的是一个后退的样式,而且鼠标放上去会有文字Back提示。

<Button Content="摩天轮" ToolTipService.ToolTip="Back"
                Style="{StaticResource NavigationBackButtonNormalStyle}" />  

ToggleSwitch

这个控件和Button很像,它像开关一样。

<ToggleSwitch x:Name="toggleSwitch1" Header="NoMasp Toggle" 
      OnContent="On" OffContent="Off" Toggled="ToggleSwitch_Toggled" 
      Margin="409,468,0,227"/>

<ToggleSwitch x:Name="toggleSwitch2" Header="NoMasp Toggle" 
     OnContent="On" OffContent="Off" IsOn="True" 
     Toggled="ToggleSwitch_Toggled" Margin="409,565,0,130"/>

这里写图片描述

MessageDialog

这控件和Button一起讲还蛮合适的,我们随意添加一个Button,然后写好Click事件如下。

private async void Button_Click(object sender, RoutedEventArgs e)
{
    Windows.UI.Popups.MessageDialog messageDialog =
        new Windows.UI.Popups.MessageDialog("噢,你刚刚踩到了地雷!");
    await messageDialog.ShowAsync();
}

注意要在函数上加上async表示异步。

这里写图片描述

如果需要预览效果,可以参见教程随后的“用浮出控件做预览效果”。

ComboBox

ComboBox提供了下拉列表,自然也是一个很常用的控件。

<ComboBox Height="50" Width="200" Name="cbox1"  SelectionChanged="cbox1_SelectionChanged" Margin="17,47,1049,671">
     <x:String>Select 1</x:String>
     <x:String>Select 2</x:String>
     <x:String>Select 3</x:String>
     <x:String>Select 4</x:String>
</ComboBox>

这里写图片描述

这里写图片描述

ListBox

ListBox控件和ComboBox很相似,都可以让用户选择已经嵌入在列表中的选项。用法如下:

<ListBox x:Name="listBox1" SelectionChanged="listBox1_SelectionChanged" Width="100">
    <x:String>Item 1</x:String>
    <x:String>Item 2</x:String>
    <x:String>Item 3</x:String>
</ListBox>

DatePicker、TimePicker

Winows平台设置时间的控件倒是很有特色,就是DatePicker和TimePicker。

<DatePicker Foreground="Red" Header="NoMasp Date" Margin="3,177,0,533"/>
<TimePicker Foreground="Green" Header="NoMasp Time" Margin="3,246,0,464" Width="289"/>    

以下既是截图,也是写这篇教程的时间。
这里写图片描述

这个控件的更多介绍也在教程随后的“时间控件的更多介绍”中。

FlipView

FlipView是一个可以让用户逐个浏览的项目集合的控件,下面是相关的示例代码。CommonAssets文件夹完全可以定义在Shared目录下,这样WP也可以拿来用了。

<FlipView>
    <Image Source="CommonAssets/5083.jpg"/>
    <Image Source="CommonAssets/5503.jpg"/>
    <Image Source="CommonAssets/6121.jpg"/>
</FlipView>

这里写图片描述

除此之外呢,我们还可以在后台代码中添加,下面的第二段代码和第一段类似,不过是用的List。

FlipView flipView = new FlipView();
flipView.Items.Add("Item 1");
flipView.Items.Add("Item 2");
flipView.SelectionChanged += filpView_SelectionChanged;
grid1.Children.Add(flipView);
List<String> listItems = new List<string>();
listItems.Add("Item 1");
listItems.Add("Item 2");                                                                                                       
FlipView flipView = new FlipView();
flipView.ItemsSource = listItems;
flipView.SelectionChanged += filpView_SelectionChanged;          
grid1.Children.Add(flipView);

除了这2种方式之外呢,用CollectionViewSource来绑定数据也是完全没问题的。

<Page.Resources>   
    <CollectionViewSource x:Name="collectionVSFlipView" Source="{Binding Items}"/>
</Page.Resources>

上面是一段资源文件,然后FlipView ListView的ItemsSource添加静态资源绑定就OK了。

<FlipView x:Name="flipView" 
          ItemsSource="{Binding Source={StaticResource collectionVSFlipView}}"/>

如果大家自己试过FlipView就会发现它的图片资源等都是左右滚动的,如果要用上下滚动呢?那就用下面这个ItemsPanelTemplate模板就好了。

<FlipView.ItemsPanel>
     <ItemsPanelTemplate>
          <VirtualizingStackPanel Orientation="Vertical"/>
     </ItemsPanelTemplate>
</FlipView.ItemsPanel>

ScrollBar

如果有缩放图片,并且可以滚动以查看图片的需要,那么就可以用ScrollBar啦。这主要是能留给图片的位置太小以至于图片无法全部显示出来。

<ScrollViewer ZoomMode="Enabled" MaxZoomFactor="12" HorizontalScrollMode="Enabled" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" VerticalScrollMode="Enabled" Height="200" Width="200" Margin="363,35,803,533">

    <Image Source="CommonAssets/6121.jpg" Height="400" Width="400"/> 
</ScrollViewer>

这里写图片描述

Viewbox

还有一个控件则可以将图片等缩放到指定的大小的,那就是Viewbox。大家看看下面这个图,是不是很炫酷呢。

    <Viewbox MaxHeight="33" MaxWidth="33" Margin="23.5,35,-26,-35">
            <Image Source="CommonAssets/5503.jpg" Opacity="0.9 "/>
        </Viewbox>
        <Viewbox MaxHeight="66" MaxWidth="66" Margin="26,35,-26,-35">
            <Image Source="CommonAssets/5503.jpg" Opacity="0.6"/>
        </Viewbox>
        <Viewbox MaxHeight="99" MaxWidth="99" Margin="26,35,-26,-35">
            <Image Source="CommonAssets/5503.jpg" Opacity="0.3"/>
        </Viewbox>

这里写图片描述

GridView

相信大家都已经看过了GridView控件,很多Modern应用都会采用的。其和ComboBox挺类似的。

<GridView x:Name="gView1" SelectionChanged="gView1_SelectionChanged">
    <x:String>Item 1</x:String>
    <x:String>Item 2</x:String>
    <x:String>Item 3</x:String>
</GridView>

HyperlinkButton

HyperlinkButton既可以作为Button来用,也可以用来做超链接。

<HyperlinkButton Content="NoMasp--优快云" NavigateUri="http://blog.youkuaiyun.com/nomasp" />

ProgressBar

相信大家都挺喜欢玩进度条的吧?我本人倒是觉得相比于Win7及Vista等,Win8的进度条变得更加有意思了。

<ProgressBar x:Name="progressBar1" IsIndeterminate="True" Width="100" Margin="607,377,659,385"/>
<ProgressBar x:Name="progressBar2" Value="70 " Width="100" Margin="607,352,659,410"/>

第一个图是运行中的进度条啦;第二个图中的上图也就是progressBar1,其Value为70的确定进度的进度条,下图则是progressBar2,是运行中的进度条在设计器中的静止状态。

这里写图片描述

ProgressRing

环形的进度条会不会更好玩呢?

<ProgressRing x:Name="progressRing1" IsActive="True" />

这里写图片描述

Slider

比如说win8上的音量呀、屏幕亮度呀,这些地方都用到了滑动条。这里来看看它的ThumbToolTipValueConverter属性吧。为了将值绑定到Slider上,我们需要有一个类,这个类需要一个为数据绑定提供值转换的接口。可视化元素也就是Slider为绑定目标,其有2个方向:数据源->数据->绑定目标,绑定目标->数据->数据源。

我们需要写一个类,可以直接在MainPage.xaml.cs下写,但更好是单独新建一个类,再考虑到这个是通用应用,所以将类新建到Shared下比较合适。

public class ThumbToolTipValueConverter : Windows.UI.Xaml.Data.IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if(value is double)
        {
                double dValue= System.Convert.ToDouble(value);
                return dValue;                
        }
        return null;
     }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        return null;
    }
}

然后添加以下代码作为本地实例化的资源即可。

<Page.Resources>
   <local:ThumbToolTipValueConverter x:Key="thumbToolTipValueC"/>
</Page.Resources>

最后就是传说中的本体啦。

<Slider Width="200" Height="50" Name="slider1"    
      ThumbToolTipValueConverter="{StaticResource thumbToolTipValueC}" />

这里写图片描述

我们还可以添加一个Button和TextBlock,让点击来在TextBlock上显示Slider的Value。

private void btnGetSliderValue_Click(object sender, RoutedEventArgs e)
{
    tblockSlider.Text = slider1.Value.ToString();
}

这里写图片描述

用浮出控件做预览效果

在前面学习控件的时候,我们已经见过了MessageDialog了,关于Button还有一个浮出控件Flyout哦。具体是怎样用呢?接下来就一起看看。

我们还是延续前面的那个示例好了,那么,代码来了。

        <Button x:Name="btnWhat" Content="这是什么?">
            <Button.Flyout>
                <Flyout>
                    <StackPanel>
                        <TextBlock Width="430" Style="{StaticResource BaseTextBlockStyle}"
                                   Text="噢!你刚刚又踩到地雷了,要撤销吗?" Foreground="Red" FontSize="25"/>
                        <Button Click="btnUndo_Click" Margin="12" Content="撤销"/>
                    </StackPanel>
                </Flyout>
            </Button.Flyout>
        </Button>

当我们点击了撤销按钮后,当然需要btnWhat按钮的Flyout消失掉,这个嘛,也只要1行代码啦。另外这个踩雷的逻辑这里就不展开啦.

private void btnUndo_Click(object sender, RoutedEventArgs e)
{
     btnWhat.Flyout.Hide();
}

更为重要的是在于这些在WP8上也是通用的,这才是核心所在。既然这一篇教程主要是浮出控件,如果可以借助浮出产生预览图像的效果会不会很棒呢?先来看张运行截图吧。

这里写图片描述

以下都是代码啦,什么Binding呀之类的都不用管啦。需要注意的地方也就是那些Height和Width可能需要拿来调整一下。

   <Page.Resources>
        <Flyout x:Key="ResourceFlyoutImage" Placement="Right">                            
            <Image Source="{Binding Path=Source}" MaxHeight="800" MaxWidth="1400" Stretch="Uniform"/>
            <Flyout.FlyoutPresenterStyle>
                <Style TargetType="FlyoutPresenter">
                    <Setter Property="MinHeight" Value="900"/>
                    <Setter Property="MinWidth"  Value="1600"/>
                    <Setter Property="BorderThickness" Value="3"/>
                    <Setter Property="Background" Value="Wheat"/>
                    <Setter Property="BorderBrush" Value="Green"/>
                    <Setter Property="ScrollViewer.ZoomMode" Value="Enabled"/>        
                </Style>
            </Flyout.FlyoutPresenterStyle>
        </Flyout>
    </Page.Resources>    

    <Grid>
        <StackPanel HorizontalAlignment="Left" Orientation="Vertical">
            <Image Source="Assets/14152.jpg" Width="100" Height="100" Margin="12" Tapped="img_Tapped"  
                   FlyoutBase.AttachedFlyout="{StaticResource ResourceFlyoutImage}"                        
                   DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"/>

            <Image Source="Assets/14158.jpg" Width="100" Height="100" Margin="12" Tapped="img_Tapped"  
                   FlyoutBase.AttachedFlyout="{StaticResource ResourceFlyoutImage}"                                                 
                   DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"/>

            <Image Source="Assets/14160.jpg" Width="100" Height="100" Margin="12" Tapped="img_Tapped"    
                   FlyoutBase.AttachedFlyout="{StaticResource ResourceFlyoutImage}"                           
                   DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"/>

            <Image Source="Assets/14164.jpg" Width="100" Height="100" Margin="12" Tapped="img_Tapped"      
                   FlyoutBase.AttachedFlyout="{StaticResource ResourceFlyoutImage}"                                                  
                   DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"/>
        </StackPanel>
    </Grid>
private void img_Tapped(object sender, TappedRoutedEventArgs e)
{
    FlyoutBase.ShowAttachedFlyout((FrameworkElement)sender);
}             

同样的,在WP上也是可以得哦,一下是做了些修改后的XAML代码啦。正如大家所见,我把图片都缩小了,Placement也设置成了Top,StactPanel的属性也做了修改。

    <Page.Resources>
        <Flyout x:Key="ResourceFlyoutImage" Placement="Top">
            <Image Source="{Binding Path=Source}" MaxHeight="600" MaxWidth="400" Stretch="Uniform"/>
            <Flyout.FlyoutPresenterStyle>
                <Style TargetType="FlyoutPresenter">
                    <Setter Property="MinHeight" Value="600"/>
                    <Setter Property="MinWidth"  Value="400"/>
                    <Setter Property="BorderThickness" Value="3"/>
                    <Setter Property="Background" Value="Wheat"/>
                    <Setter Property="BorderBrush" Value="Green"/>
                    <Setter Property="ScrollViewer.ZoomMode" Value="Enabled"/>
                </Style>
            </Flyout.FlyoutPresenterStyle>
        </Flyout>
    </Page.Resources>

    <Grid>
        <StackPanel VerticalAlignment="Bottom" Orientation="Horizontal">
            <Image Source="Assets/14152.jpg" Width="72" Height="60" Margin="12" Tapped="img_Tapped"  
                   FlyoutBase.AttachedFlyout="{StaticResource ResourceFlyoutImage}"                        
                   DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"/>

            <Image Source="Assets/14158.jpg" Width="72" Height="60" Margin="12" Tapped="img_Tapped"  
                   FlyoutBase.AttachedFlyout="{StaticResource ResourceFlyoutImage}"                                                 
                   DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"/>

            <Image Source="Assets/14160.jpg" Width="72" Height="60" Margin="12" Tapped="img_Tapped"    
                   FlyoutBase.AttachedFlyout="{StaticResource ResourceFlyoutImage}"                           
                   DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"/>

            <Image Source="Assets/14164.jpg" Width="72" Height="60" Margin="12" Tapped="img_Tapped"      
                   FlyoutBase.AttachedFlyout="{StaticResource ResourceFlyoutImage}"                                                  
                   DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"/>
        </StackPanel>
    </Grid>

看样子效果还不错嘛。

这里写图片描述

这里写图片描述

这里写图片描述

时间控件的更多介绍

在前面我们走马观花地介绍了一大堆控件,其中自然也包括这DatePicker和TimePicker,那么稍微高级些的用法呢?

如果你想做一个关于健身、闹钟等的App,那么不可避免的会用到时间这些控件了。

<DatePicker x:Name="datePicker" Header="NoMasp Date" Foreground="Beige"/>          
<Button x:Name="btnOK" Click="btnOK_Click" Content="确定" Foreground="Cyan" Margin= "292,378,0,352" >
     <Button.Flyout>
          <Flyout>
              <TextBlock x:Name="tblock1" Foreground="Fuchsia"/>
          </Flyout>
     </Button.Flyout>
</Button>

那么我们可能需要所选定的时间是未来时间,也就是比应用运行时的时间要大。获取当前选中的时间给程序的其他部分使用也是很简单的,我这里的year等都在之前定义过了哦,在函数内定义可是不明智的哟。

private void btnOK_Click(object sender, RoutedEventArgs e)
{
    if(datePicker.Date>DateTimeOffset.Now)
        tblock1.Text = string.Format("你所选中的时间是:{0}。", datePicker.Date.ToString("D"));
    else
        tblock1.Text = "噢!你想要穿越吗?";

    year = datePicker.Date.Year;
    month = datePicker.Date.Month;
    day = datePicker.Date.Day;   
}        

有意思的事情又来了,如果你是想要做一个时间囊,默认的时间就是10年之后,那么DatePicker的初始事件如果正好就是10年后不是非常好吗。那么我们要做的呢,首先就是给DatePicker的Loaded写一条事件啦。(虽然我觉得App是保存不了10年的)

private void datePicker_Loaded(object sender, RoutedEventArgs e)
{
    datePicker.Date = DateTimeOffset.Now.AddYears(10);
}

如果不想兴师动众去用DatePicker的Loaded,那么也可以直接在后台代码中这样写。

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    datePicker.Date = DateTimeOffset.Now.AddYears(10);
}

我还做了一个小测试呢,在Loaded事件中让时间增加11年,在OnNavigatedTo事件中让时间增加10年,结果——结果是增加了11年啦,看来还是自家的Loaded更厉害。

接下来就是TimePicker啦,回到健身的话题,假设哈,6点到18点才适合运动,那么我们的Microsoft Band就做了以下这么个要求(开玩笑啦)。

    private void btnOK_Click(object sender, RoutedEventArgs e)
        {
            TimeSpan startTime = new TimeSpan(6, 0, 0);
            TimeSpan endTime = new TimeSpan(18, 0, 0);

            if(timePicker.Time>=startTime&&timePicker.Time<=endTime)
            {
                tblock1.Text = string.Format("这段时间运动都是很好的哦——{0}。", timePicker.Time.ToString());
            }
            else
            {
                tblock1.Text = "此时间吧不适合运动的吧?";
            }       
        }        

也许你还想控制手环上时间选择器的初始时间,那么代码来了。

protected override void OnNavigatedTo(NavigationEventArgs e)
{                                              
     timePicker.Time = new TimeSpan(23, 0, 0);
}

作为强迫症患者呢,每次我设定闹钟的时候都要设置在一个比较好的时间,比如被5整除啦、质数啦。这里可以用MinuteIncrement属性来控制分钟的增量哟,比如增量为5呀。从小学起就飞得把电子手表的时间给设置成24小时制的,这个也是可以实现的,ClockIdentifier设置成24HourClock就搞定啦。

应用栏

基本的用法我们在教程前面的“页面布局与基本导航”中已经讲过了,这里继续补充关于应用栏的更多用法。

Icon

在之前的学习中,我们知道Icon属性中有很多很多系统预定义,但也许这些还是不够的,现在就来增加几种用法。

字符集应用

<AppBarToggleButton Label="Sigma" Click="AppBarButton_Click">
    <AppBarToggleButton.Icon>
        <FontIcon Glyph="&#x03A3;"/>
    </AppBarToggleButton.Icon>
</AppBarToggleButton>

关于更多字符集的应用请访问维基百科。

PathIcon

我们也可以用路径来绘制一个属于自己的图形哦,下面的图形大概就是9点钟的样子啦。

<AppBarToggleButton Label="Time" Click="AppBarButton_Click">
    <AppBarToggleButton.Icon>                              
        <PathIcon Data="F1 M 20,20 21,1L 21,21L 8,21"/>
    </AppBarToggleButton.Icon>
</AppBarToggleButton>

这里写图片描述

如何适应不同的分辨率

如何适应不同的分辨率这也是值得我们去解决的问题,毕竟不论是从8英寸的平板还是25英寸的台式机,甚至还有4英寸至7英寸的手机,在应用栏按钮太多而屏幕不够大时,多余的按钮该怎么办呢?

默认情况下,应用栏图标的宽度都是确定好的100像素哦。那么我们先来看两张图片好了,由于Windows 10是可以直接调整Modern应用的大小的(而不是windows 8那种只能全屏显示),所以我直接拉伸Modern大小以模拟分辨率的概率啦。

这里写图片描述

这里写图片描述

    <Page.BottomAppBar>
        <AppBar x:Name="bottomAppBar" IsSticky="True">
            <Grid>          
                <StackPanel x:Name="leftBottomAppBar" 
                            Orientation="Horizontal">
                    <AppBarButton Label="Like" Icon="Like"/>
                    <AppBarButton Label="Dislike" Icon="Dislike"/>
                    <AppBarButton Label="Delete" Icon="Delete"/>
                    <AppBarButton Label="Download" Icon="Download"/>
                    <AppBarButton Label="Pin" Icon="Pin"/>
                </StackPanel>
                <StackPanel x:Name="rightBottomAppBar" 
                        Orientation="Horizontal" HorizontalAlignment="Right">
                    <AppBarButton Label="Play" Icon="Play"/>
                    <AppBarButton Label="Pause" Icon="Pause"/>
                    <AppBarButton Label="Stop" Icon="Stop"/>
                    <AppBarButton Label="Previous" Icon="Previous"/>
                    <AppBarButton Label="Next" Icon="Next"/>
                </StackPanel>
            </Grid>
        </AppBar>
    </Page.BottomAppBar>

这里为了调试更加方便,所以使用了IsSticky属性。AppBarButton还有一个很重要的属性哟,之前用不到,不过这里就是核心成员了呢,它就是IsCompact。这个属性可以让应用栏按钮只显示图标而不显示文字,也就是Label啦。那么我们的工作就要围绕这个属性来展开了。

我们可以这样假设,有一个函数,它有一个布尔变量的参数,参数为真的话呢,那么所有的这些AppBarButton的IsCompact属性也为真。在以下这段代码中,我们先将bottomAppBar的自对象选取为root,这样一来的话呢,如果应用中还有顶部的应用栏,就不会相互干扰啦。然后逐步取出root和panel中的自对象就好咯。

     private void AppBarButtonCompact(bool isCompact)
        {
            Panel root = bottomAppBar.Content as Panel;
            if(root!=null)
            {
                foreach(Panel panel in root.Children)
                {
                    foreach (ICommandBarElement child in panel.Children)
                    {
                        child.IsCompact = isCompact;
                    }
                }
            }
        }

接下来还需要判断到底需不需要启用IsCompact,那这又是由什么决定的呢,既然前面提到是因为屏幕的分辨率,也就是所应用所占用的宽度会导致应用栏发生重叠,那么答案就毫无疑问了。看到下面的代码相信大家都明白了,至于为何是宽度的界限在1000呢,那是因为有10个AppBarButton,前面也说了它们的宽度是100。(不带Label的话呢,就只需要60像素啦。)

     void AppSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (e.NewSize.Width != e.PreviousSize.Width)
            {
                if (e.NewSize.Width < 1000)
                {
                    AppBarButtonCompact(true);
                }
                else
                {
                    AppBarButtonCompact(false);
                }
            }
        }

来张图片以示搞定这个问题了吧。

这里写图片描述

但是像我这么钻牛角尖的人,10个AppBarButton用这种方式搞定了,那20个呢?我们就来演示一下,把之前XAML中的AppBarButton复制粘贴一番。如果是2K、4K的屏幕应对20个没问题啊,但我这1920X1080的屏幕就放不下了。

这里写图片描述

那么这又有什么办法可以解决的吗?当然有啦,将这20个图标切成2列就好啦。我们首先在Grid中添加一行。

<Grid.RowDefinitions>      
    <RowDefinition Height="auto"/>                     
    <RowDefinition Height="auto"/>                
</Grid.RowDefinitions>

再通过下面这张方式来调整它处于哪一行,以及在水平方向的右侧还是左侧。这里我将两行都设置在右侧啦。

leftBottomAppBar.SetValue(Grid.RowProperty, 1);
leftBottomAppBar.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Right);           

当然了,这样一来就可以放40个AppBarButton啦,如果缩小应用的大小的话为了容纳更多还可以用IsCompact属性呢。不过没有哪个应用做成这样吧。

这里写图片描述

另外呢,如果把应用栏设计成这样的话。

<Page.BottomAppBar>   
   <AppBar x:Name="bottomAppBar" IsSticky="True">            
      <Grid>                
         <Grid.ColumnDefinitions>                      
             <ColumnDefinition Width="*"/>                    
             <ColumnDefinition Width="*"/>                
         </Grid.ColumnDefinitions>               
         <StackPanel Grid.Column="0" x:Name="leftBottomAppBar"  Orientation="Horizontal" HorizontalAlignment="Left">                                     
             <AppBarButton Label="Like" Icon="Like"/>                
             <AppBarButton Label="Dislike" Icon="Dislike"/>           
             <AppBarButton Label="Delete" Icon="Delete"/>                 
             <AppBarButton Label="Download" Icon="Download"/>       
             <AppBarButton Label="Pin" Icon="Pin"/>                
         </StackPanel>     
         <StackPanel Grid.Column="1" x:Name="rightBottomAppBar" Orientation="Horizontal" HorizontalAlignment="Right">                                                     
             <AppBarButton Label="Play" Icon="Play"/>       
             <AppBarButton Label="Pause" Icon="Pause"/>       
             <AppBarButton Label="Stop" Icon="Stop"/>         
             <AppBarButton Label="Previous" Icon="Previous"/>       
             <AppBarButton Label="Next" Icon="Next"/>        
         </StackPanel>   
      </Grid>   
   </AppBar>  
</Page.BottomAppBar>

那么对于Windows 10,在拉伸的过程中,中间部分的控件就会慢慢消失啦。以下这张图片呢,是我在拉伸到中间有2个控件刚好重叠的时候啦。至于把AppBarButton设计成这样是好是坏大家自己决定咯,我反正觉得这样不好呢。不过有意思的是,即便如此,它们彼此的Click事件还都是有效的噢,会区分左右两部分,而不会叠在一起。

这里写图片描述

当然啦,这个的应用远不是应用栏这么简单哟,对于其他的前景,比如有两个TextBlock在屏幕左右两侧,当应用把收缩变小之后也可以让这个TextBlock叠成2层在屏幕的一边。

在应用栏上添加菜单

我们都见过有菜单的应用栏按钮对吧,这个的实现其实也挺简单的。用Flyout属性就好了。

<Page.BottomAppBar>        
    <CommandBar> 
        <AppBarButton Icon="Rotate" Label="Rotate">                
            <AppBarButton.Flyout>                    
                <MenuFlyout>   
                   <MenuFlyoutItem Text="Rotate 90" Click="MenuFlyoutItem_Click" Tag="Rotate90"/>           
                   <MenuFlyoutItem Text="Rotate 180" Click="MenuFlyoutItem_Click" Tag="Rotate180"/>      
                   <MenuFlyoutItem Text="Rotate 270" Click="MenuFlyoutItem_Click" Tag="Rotate270"/>                    
               </MenuFlyout>                
           </AppBarButton.Flyout>            
       </AppBarButton>     
   </CommandBar>   
</Page.BottomAppBar>

Tag属性,就相当于做一个标签。下面这段代码就让Flyout菜单发挥作用了。

private void MenuFlyoutItem_Click(object sender, RoutedEventArgs e)
{
    MenuFlyoutItem selectedItem = sender as MenuFlyoutItem;

    if (selectedItem != null)
    {
        if (selectedItem.Tag.ToString() == "Rotate90")
        {
            DoRotate(90);
        }
        else if (selectedItem.Tag.ToString() == "Rotate180")
        {
            DoRotate(180);
        }
        else if (selectedItem.Tag.ToString() == "Rotate270")
        {
            DoRotate(270);
        }
    }
}
Contents 开发桌面应用 设置开发环境 系统要求 安装开发人员工具 启用设备进行开发 开发人员模式功能和调试 创建一个开发者帐户 入门 概述 适用于 Windows 应用的 Visual Studio 模板 生成适用于 Windows 11 的应用 让你的应用Windows 11 上出色表现 设计和 UI 概述 Windows 11 中的设计 Windows 11 设计原则 Windows 11 签名体验 Geometry 颜色 分层和提升 材料 图标 版式 设计基础知识 概述 应用设计简介 导航基础知识 概述 实现基本导航 导航历史记录和向后导航 命令基础知识 内容基础知识 教程 创建用户界面 创建自适应布局 设置控件的样式 布局 概述 页面布局 屏幕大小和断点 响应式设计技术 使用 XAML 的布局 显示多个视图 显示多个视图 使用 AppWindow 使用 ApplicationView 对齐、边距和填充 面板 概述 教程:使用布局面板 拆分视图 自定义面板 自定义面板示例:BoxPanel 附加的布局 转换 概述 3D 透视效果 Z 深度和阴影 控制 概述 控件和事件简介 命令处理简介 基本输入 按钮 复选框 组合框和列表框 超链接 单选按钮 评分控件 滑块 切换开关 集合 概述 列表视图和网格视图 翻转视图 PipsPager 树视图 ItemsRepeater 项目容器和模板 项目容器和模板 数据模板选择 列表视图项模板 网格视图项模板 选择和交互 集合命令处理 “选择模式”概述 轻扫 下拉刷新 筛选集合 其他集合选项和自定义 反转列表 嵌套 UI 对话框和浮出控件 概述 对话框 浮出控件 教学提示 窗体 媒体、图形和形状 动画图标 图像和图像画笔 墨迹 媒体播放 自定义传输控件 形状 Web 视图 菜单和工具 菜单和上下文菜单 命令 命令浮出控件 菜单浮出控件和菜单 导航 痕迹导航 列表/详细信息 导航视图 Pivot 选项卡视图 人员 联系人卡片 头像图片 选取器 颜色选取器 日期和时间控件 日历日期选取器 日历视图 日期选取器 时间选取器 滚动和布局 Expander 滚动和平移控件 语义式缩放 双窗格视图 状态和信息 进度 工具提示 信息 文本 概述 自动建议框 文本块 RTF 块 文本框 富编辑框 密码框 数字框 标签 内容链接 手写视图 样式 概述 颜色 版式 图标 概述 应用图标和徽标 Segoe MDL2 图标 亚克力 Mica 显示焦点 声音 写入样式 XAML 画笔 XAML 样式 XAML 控件模板 ResourceDictionary 和 XAML 资源引用 XAML 主题资源 间距 角半径 移动 概述 计时和缓动 方向性和引力 运动练习 页面过渡 连贯的动画 视差 XAML 中的动画 属性动画 情节提要动画 关键帧以及缓动函数动画 Shell Toast 通知 UX 指南 发送本地 Toast C# 应用 C++ UWP 应用 C++ WRL 应用 其他应用 Toast 内容 Content 架构 计划 toast 其他功能 自定义音频 进度条 挂起更新 自定义时间戳 集合 标头 通知侦听器 已过时 锁屏提醒通知 推送通知 概述 WNS 优先级 将 WNS 流量加入允许列表 由推送通知向导生成的代码 任务应用固定到任务 标题 动态磁贴 辅助磁贴 指南 固定到“开始”屏幕 固定到任务 桌面应用程序 磁贴内容 磁贴内容架构 特殊磁贴模板 发送本地磁贴通知 可追踪的磁贴通知 主要磁贴 API 磁贴和 Toast 通知的语言、比例和高对比度支持 杂项 通知可视化工具 通知传递方法 通知通道类型 使用 Webpush 和 VAPID 的备用通道 定期通知 输入和交互 概述 输入基础版 指针输入 凝视 笔和 Windows Ink 教程:向应用添加墨迹支持 识别笔划墨迹 存储和检索笔划墨迹 添加 InkToolbar 触摸 鼠标 Keyboard 访问键 键盘加速键 键盘事件 适用于键盘、手柄、遥控器和辅助功能工具的焦点导航 编程焦点导航 响应触摸键盘的存在 使用输入范围更改触摸键盘 文本输入 自定义文本输入 文本缩放 选择文本和图像 输入法编辑器 输入法编辑器要求 ......
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值