1、创建自定义控件
为了代码易于管理,在这里,我把弹出画面定义为一个自定义控件。也就是包含一个xaml文件和相关的代码文件。如下图所示,如何创建自定义控件:
选择用户控件,输入名称就可以了。
下图是创建好的画面
我将控件文件SearchFlayout存放在Flayouts文件夹下。
在xaml文件中添加如下代码
<UserControl x:Class="DevDiv_AppBar.Flayouts.SearchFlayout" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:DevDiv_AppBar.Flayouts" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid> <Popup x:Name="SearchPopup" IsLightDismissEnabled="True" Width="350" Height="130" > <StackPanel Background="Black"> <Border Background="#85bd" BorderThickness="4"> <StackPanel> <StackPanel Orientation="Horizontal" Margin="10"> <TextBlock Text="请输入搜索内容:" VerticalAlignment="Center" Margin="0,0,10,0" /> <TextBox Name="searchDataBox" Height="40" Width="150" FontSize="20" /> </StackPanel> <Button Click="SearchButtonClick" HorizontalAlignment="Center" Margin="10">搜索</Button> </StackPanel> </Border> </StackPanel> </Popup> </Grid> </UserControl>
在代码中,需要提醒的是Popup的属性IsLightDismissEnabled="True"。这表示当用户点击或者触摸屏幕的任意位置,不包括Popup的位置,pop-up画面是否消失。当把Popup用作弹出画面时,这个属性必须设置为True,因为这是才符合基本的弹出画面(flyout)用户体验。
如下图所示,我们还可以在设计器中,看到自定义控件长什么样
在上面的代码中需要注意的是创建弹出画面必须使用Popup控件,至于Popup控件里面的内容就按需而定即可。我在这里用了TextBlock、TextBox和Button三个控件,当然还有一个StackPanel容器控件。
这样我们xaml文件就基本写完了。下面我们开始编写控件的C#代码
2、编写自定义控件代码
在这里,自定义控件中主要实现两个功能:显示控件本身和响应控件提供的相关用户交互操作大家看下面两个函数Show方法主要就是将自己显示出来。SearchButtonClick是响应自定义控件中的搜索按钮事件。
注意:在Show方法中有一行代码如下,是用来计算当前弹出画面需要显示的位置,后面会有讲解(由于目前的版本中微软并没有提供相关好的方法来获取显示的位置,所以需要自行计算,希望在windows 8正式版发布之后,能解决这个问题)
FlyoutHelper.ShowRelativeToAppBar(SearchPopup, page, appbar, button);
public void Show(Page page, AppBar appbar, Button button) { SearchPopup.IsOpen = true; FlyoutHelper.ShowRelativeToAppBar(SearchPopup, page, appbar, button); } private void SearchButtonClick(object sender, RoutedEventArgs e) { SearchPopup.IsOpen = false; }
3、定位弹出的控件(画面)
在这里我创建了一个FlyoutHelper类,其中定义了一个静态方法ShowRelativeToAppBar。这个方法计算出相关按钮上显示的Popup的正确位置,这样做,需要传入Popup控件、包含AppBar的Page、AppBar控件和被点击的button按钮。这个方法并不好,但这是我发现的可以获得flyout准确位置的唯一方法。具体代码如下:
namespace DevDiv_AppBar.Flayouts { class FlyoutHelper { public static void ShowRelativeToAppBar(Popup popup, Page page, AppBar appbar, Button button) { Func<UIElement, UIElement, Point> getOffset = delegate(UIElement control1, UIElement control2) { return control1.TransformToVisual(control2).TransformPoint(new Point(0, 0)); }; Point popupOffset = getOffset(popup, page); Point buttonOffset = getOffset(button, page); popup.HorizontalOffset = buttonOffset.X - popupOffset.X - (popup.ActualWidth / 2) + (button.ActualWidth / 2); popup.VerticalOffset = getOffset(appbar, page).Y - popupOffset.Y - popup.ActualHeight; if (popupOffset.X + popup.HorizontalOffset + popup.ActualWidth > page.ActualWidth) { popup.HorizontalOffset = page.ActualWidth - popupOffset.X - popup.ActualWidth; } else if (popup.HorizontalOffset + popupOffset.X < 0) { popup.HorizontalOffset = -popupOffset.X; } } } }
代码会将Popup定位在与其相关的AppBar按钮的上方,如果Popup从屏幕的左侧或右侧消失那么Popup将被重新定位,由于这代码比较恶心,我就不细讲了,希望在windows 8正式版发布之后,这个问题会得到解决。
4、在程序中使用弹出画面
将刚刚定义的控件添加到MainPage.xaml中,代码如下所示。
这里需要将名称空间添加进来using:DevDiv_AppBar.Flayouts 这样才能使用Flayouts中定义的控件。
下面的代码中,添加自定义控件是这行代码
<flyouts:SearchFlayout x:Name="SearchFlayout"/>
虽然这里并不是马上就显示出弹出画面,但是我们也需要把自定义控件声明为主程序布局的一部分。
<Page x:Class="DevDiv_AppBar.MainPage" IsTabStop="false" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:DevDiv_AppBar" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:flyouts="using:DevDiv_AppBar.Flayouts" mc:Ignorable="d"> <Grid Background ="PaleGoldenrod"> <Image HorizontalAlignment="Left" Height="200" Margin="495,215,0,0" VerticalAlignment="Top" Width="295" Source="Assets/icon.png"/> <flyouts:SearchFlayout x:Name="SearchFlayout"/> </Grid> </Page>
5、显示弹出画面
现在代码基本编写完毕了,剩下的任务就是当用户点击AppBar上的搜索按钮时,将弹出画面显示出来即可。
我在MainPage.xaml.cs中添加如下代码:
并将该方法与AppBar的搜索按钮Click事件关联起来即可
private void AppBarButtonClick(object sender, RoutedEventArgs e){ if (e.OriginalSource == AppBarSearchButton) { SearchFlayout.Show(this, this.BottomAppBar, (Button)e.OriginalSource); } }