zoukankan      html  css  js  c++  java
  • C#+XAML的Metro应用开发入门(三)

    知识点

    1.了解和使用Windows 8应用中的导航;

    2.利用导航和一些常用控件实现一个文本阅读器;

    一、Windows 8中的导航

             Windows 8中的导航主要通过Frame中的Navigate方法进行,Navigate的原型如下:

    •     public bool Navigate(Type sourcePageType);
    •     public bool Navigate(Type sourcePageType, object parameter);

             可以看出,在页面导航的过程中可以传递object类型的参数,这使得页面之间的数据传递非常灵活,但是Windows 8的挂起恢复机制要求传递的参数能够可序列化,因此在进行页面间的数据传递时,对参数的类型和组织方式也要有所考虑。

    二、在Windows 8应用中使用导航

             为了简单起见,我们设计了如下功能的TXT文本阅读器:

             1.在首页中打开一个文件选择器,选择一个TXT文件;

             2.在正文页显示TXT文章的标题和内容;

      创建工程

      打开Visual Studio,选择文件〉新建项目,在新建对话框中选择Visual C#模版,建立一个空的应用Blank App(XAML),名称可以自己选择,点击确定即可完成项目的创建。

         视图设计

         主页仅仅放置了一个按钮,布局比较简单,代码如下:

    <Page
        x:Class="TextReader.MainPage"
        IsTabStop="false"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:TextReader"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
            <Button Content="打开" Width="120" HorizontalAlignment="Center" VerticalAlignment="Center" Click="OnOpen"/>
        </Grid>
    </Page>

         在正文页我们选择创建一个基本页,Visual Studio会为我们生成一个带后退按钮和标题的页面,我在这个基础上进行改造,加入一个装在ScrollViewer容器中的TextBlock来显示文章内容,同时采用数据绑定将标题和内容绑定至不同的数据,代码如下:

    <common:LayoutAwarePage
        x:Name="pageRoot"
        x:Class="TextReader.ArticlePage"
        DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
        IsTabStop="false"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:TextReader"
        xmlns:common="using:TextReader.Common"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Page.Resources>
    
            <!-- TODO: Delete this line if the key AppName is declared in App.xaml -->
            <x:String x:Key="AppName">My Application</x:String>
        </Page.Resources>
    
        <!--
            This grid acts as a root panel for the page that defines two rows:
            * Row 0 contains the back button and page title
            * Row 1 contains the rest of the page layout
        -->
        <Grid Style="{StaticResource LayoutRootStyle}">
            <Grid.RowDefinitions>
                <RowDefinition Height="140"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
    
            <!-- Back button and page title -->
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
                <TextBlock x:Name="pageTitle" Grid.Column="1" Text="{Binding ArticleTitle}" Style="{StaticResource PageHeaderTextStyle}"/>
            </Grid>
            <ScrollViewer Grid.Row="1" >
                <TextBlock Text="{Binding ArticleContent}" FontSize="24" Margin="20" TextWrapping="Wrap">
                </TextBlock>
            </ScrollViewer>
            <VisualStateManager.VisualStateGroups>
    
                <!-- Visual states reflect the application's view state -->
                <VisualStateGroup x:Name="ApplicationViewStates">
                    <VisualState x:Name="FullScreenLandscape"/>
                    <VisualState x:Name="Filled"/>
    
                    <!-- The entire page respects the narrower 100-pixel margin convention for portrait -->
                    <VisualState x:Name="FullScreenPortrait">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PortraitBackButtonStyle}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
    
                    <!-- The back button and title have different styles when snapped -->
                    <VisualState x:Name="Snapped">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedBackButtonStyle}"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" Storyboard.TargetProperty="Style">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedPageHeaderTextStyle}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Grid>
    </common:LayoutAwarePage>

         选择一个TXT文件并导航至文章正文页

         为首页中的按钮添加一个Click事件,在事件处理函数中调用FileOpenPicker来选择文件,其作用与文件选择对话框相当。选择完文件之后,我们将页面导航至文章正文页,并向其传递文章标题和内容等数据。代码如下,其中高亮显示的部分为导航操作。

    private async void OnOpen(object sender, RoutedEventArgs e)
            {
                var picker = new FileOpenPicker();
                picker.FileTypeFilter.Add(".txt");
                picker.CommitButtonText = "打开";
                picker.SettingsIdentifier = "选择一个文件";
                picker.ViewMode = PickerViewMode.List;
                picker.SuggestedStartLocation = PickerLocationId.Desktop;
                var file = await picker.PickSingleFileAsync();
                if (file != null)
                {
                    Stream stream = await file.OpenStreamForReadAsync();
                    if (stream.CanSeek)
                        stream.Seek(0, SeekOrigin.Begin);
                    if (stream.CanRead)
                    {
                        long length = stream.Length;
                        byte[] buffer = new byte[length];
                        stream.Read(buffer,0,(int)length);
    
                        List<string> bundle = new List<string>();
                        bundle.Add(file.DisplayName);
                        bundle.Add(Encoding.GetEncoding("gb2312").GetString(buffer,0,(int)length));
    
                        this.Frame.Navigate(typeof(ArticlePage), bundle);
                    }                              
                }
            }

         数据绑定

         为了有效复习数据绑定的知识,我们在文章正文页的数据呈现上也采用了数据绑定,设计了一个ArticleViewModel用呈现文章的标题和内容,这个类的设计如下:

     class ArticleViewModel : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            private string articleTitle;
            public string ArticleTitle
            {
                get
                {
                    return articleTitle;
                }
                set
                {
                    if (articleTitle != value)
                    {
                        articleTitle = value;
                        NotifyPropertyChanged("ArticleTile");
                    }
                }
            }
    
            private string articleContent;
            public string ArticleContent
            {
                get
                {
                    return articleContent;
                }
                set
                {
                    if (articleContent != value)
                    {
                        articleContent = value;
                        NotifyPropertyChanged("ArticleContent");
                    }
                }
            }
    
            public ArticleViewModel(string tile, string content)
            {
                this.articleTitle = tile;
                this.articleContent = content;
            }
    
            private void NotifyPropertyChanged(string propertyName)
            {
                if (null != PropertyChanged)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

         为了实现数据绑定,我们需要设置UI元素的DataContext属性来关联ViewModel,这里我们在文章正文页的OnNavigateTo方法中接收首页传递的文章标题和文章内容数据,构造一个ArticleViewModel实例,并将DataContext设置为该实例,代码如下:

    protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                var parameter = (List<string>)e.Parameter;
                articleViewModel = new ArticleViewModel(parameter[0], parameter[1]);
                this.DataContext = articleViewModel;
            }

             另外需要注意的是,由于文章正文页采用了基本页(LayoutAwarePage)作为了模板,系统为我们自动生成了应用挂起时的一些状态保存工作,而这个例子我们并不涉及挂起时的状态保存操作,为了避免调用这些方法,我们将OnNavigateFrom方法重载为空的方法,如下:

     protected override void OnNavigatedFrom(NavigationEventArgs e)
            {         
            }

             最终的运行效果如下图所示:

    应用运行效果图

     完整代码下载

    (原创文章,转载请注明作者schbook:seekerxu@163.com)

     

  • 相关阅读:
    汇编语言 第三章 寄存器
    汇编语言 第二章
    实验一 查看CPU和内存,用机器指令和汇编指令教程
    nginx的log、upstream和server
    高并发情况下Linux系统及kernel参数优化
    二进制方式安装docker(非root用户启动docker)
    redis
    redis配置文件详解
    Keepalived+LVS实现LNMP网站的高可用部署
    Nginx location相关配置说明
  • 原文地址:https://www.cnblogs.com/schbook/p/2621726.html
Copyright © 2011-2022 走看看