Hello Universal Windows平台(UWP)/ Windows 10

对于我最近的博客文章有关如何在便携式类库(PCL)中的Web服务,我决定为Windows 10编写客户端,这允许为运行Windows 10的每个平台创建应用程序。在此帖子中我将专注于平台桌面,平板电脑和移动显示如何基于MVVM架构创建基本应用程序。要创建Windows 10应用程序,您需要一台运行Windows 10和Visual Studio 2015的计算机。

创建基本应用程序

首先,允许我们创建一个可以在详细视图中导航到的人员列表。在此,我们将创建两页。在第一页上 mainPage.xaml. 我们将简单地显示列表:

<Page
    x:Class="HttpClientSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Main, Source={StaticResource Locator}}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <GridView ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"></GridView>

        <AppBar VerticalAlignment="Bottom" IsOpen="True" >
            <AppBarButton Icon="Add" Label="Add Person" Command="{Binding AddNewPerson}" />
        </AppBar>
    </Grid>
</Page>

用户可以选择列表的一个元素,我们将导航到允许我们编辑该人的人的详细信息。这是在的 MainViewModel.cs. 这是基于 MVVM光 实施框架:

public class MainViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private ObservableCollection<Person> _people;
    private Person _selectedPerson;

    public MainViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;
        _people = new ObservableCollection<Person>();
        ShowPerson = person => { };
        AddNewPerson = new RelayCommand(() => ShowPerson(-1));
    }

    public ObservableCollection<Person> People => _people;
    public Action<int> ShowPerson { get; set; }

    public Person SelectedPerson
    {
        get { return _selectedPerson; }
        set
        {
            if (_selectedPerson == value) return;
            _selectedPerson = value;
            RaisePropertyChanged(nameof(SelectedPerson));
            if (_selectedPerson != null) ShowPerson(_people.IndexOf(_selectedPerson));
        }
    }

    public ICommand AddNewPerson { get; private set; }

    public async Task Init()
    {
        var people = await _personService.GetPeople();

        _people.Clear();

        foreach (var person in people)
        {
            _people.Add(person);
        }
    }
}

视图模型还准备了主页上显示的人员列表。这 persondetailpage.xaml. 将允许编辑此人的第一个和姓氏:

<Page
    x:Class="HttpClientSample.PersonDetailPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Person, Source={StaticResource Locator}}"
    Loaded="PersonDetail_OnLoaded"
    mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBox Header="Firstname" Text="{Binding Firstname, Mode=TwoWay}"/>
        <TextBox Header="Lastname" Text="{Binding Lastname, Mode=TwoWay}"/>
        <Button Content="Save" Command="{Binding StoreCommand, Mode=TwoWay}" IsEnabled="{Binding HasPendingChanges}" HorizontalAlignment="Center" Margin="0,10"/>
    </StackPanel>
</Page>

选择保存时,将更新此人,所有逻辑都已实施 persondetailviewmodel.cs.:

public class PersonDetailViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private int _id;
    private string _firstname;
    private string _lastname;
    private bool _hasPendingChanges;

    public PersonDetailViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;

        StoreCommand = new RelayCommand(StorePerson, () => true);
        HasPendingChanges = false;
    }

    public bool HasPendingChanges
    {
        get { return _hasPendingChanges; }
        set
        {
            if (value == _hasPendingChanges) return;
            _hasPendingChanges = value;
            RaisePropertyChanged(nameof(HasPendingChanges));
        }
    }

    public string Firstname
    {
        get { return _firstname; }
        set
        {
            if (value == _firstname) return;
            _firstname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Firstname));
        }
    }

    public string Lastname
    {
        get { return _lastname; }
        set
        {
            if (_lastname == value) return;
            _lastname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Lastname));
        }
    }

    public ICommand StoreCommand { get; set; }

    public async Task Init(int id)
    {
        _id = id;
        var person = id > 0 ? (await _personService.GetPeople()).ToList()[id] : new Person("", "");
        Firstname = person.FirstName;
        Lastname = person.LastName;
        HasPendingChanges = false;
    }

    private async void StorePerson()
    {
        HasPendingChanges = false;

        var person = new Person(Firstname, Lastname);

        if (_id >= 0)
        {
            await _personService.UpdatePerson(_id, person);
        }
        else
        {
            await _personService.CreatePerson(person);
        }
    }
}

为了防止用户在多次调用人员的存储器时,只有在等待更改时才启用商店按钮,并且您可能希望改善生产代码中的错误处理,因为它在不存在的过程中 店员 method.

基本导航

从主页面我们实施导航 mainPage.xaml.cs. 这允许用户导航到详细信息页面。我们还通过一个导航参数,该参数包含在此基本示例中包含我们想要查看的人的数组索引:

private void ShowPerson(int personId)
{
    Frame.Navigate(typeof (PersonDetailPage), personId);
    _viewModel.SelectedPerson = null;
}

导航在Frame.Navige上完成,它将目标的类型和参数作为参数。这 选择伙伴 调用导航后,将设置为null。这是这样做的,以便用户可以第二次重新选择人。

此外,当用户将一个人添加到中 AppBar. 它将调用相同的导航方法,但在-1中传递为参数,指示没有设置索引。

此外,用户有可能导航回主页面。因此,我们必须启用我们在人详细信息页面的加载的事件处理程序中设置的后部导航,并为其添加一个事件处理程序 后退:

private void PersonDetail_OnLoaded(object sender, RoutedEventArgs e)
{
    SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
    SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
}

事件处理程序实现如下:

private void OnBackRequested(object sender, BackRequestedEventArgs backRequestedEventArgs)
{
    if (Frame.CanGoBack)
    {
        Frame.GoBack();
        backRequestedEventArgs.Handled = true;
    }
}

在Windows 10下测试应用程序时,我注意到选择硬件后按钮时调用两次导航。在事件参数中将CommentLod属性设置为True,框架被指示已被关注。

把它带到其他形式因素

创建应用程序作为通用Windows平台应用程序的一件好事是API在设备上保持相同。关于即将到来的Windows 10移动版本,我们甚至可以重用UI代码。所以我们可以在手机上运行此基本应用程序而不进行任何更改。 UI将自动采用新的表单因素。

现在当然有关更多复杂的应用程序,您将想要根据屏幕尺寸使用不同的布局,但即使您将创建自适应布局(与响应网站相同),而不是开发多个应用程序来定位不同的平台。因此,在多种形式因素中具有更少的开销和工作,可以在多种形的因素中拥有运行应用程序。

结论

在此帖子中,我们了解如何创建基本的Windows 10 UWP应用程序,包括基本导航功能以及如何实现MVVM模式。如果您来自WPF,Silverlight,Windows 8.x或Windows手机背景,您已经看到了很多元素非常熟悉。

我最近和F#一起玩过,这是目前不是一个支持UWP应用程序的支持语言。这还包括无法使用UWP应用程序共享便携式类库。如果您对我的感觉与我或想要抛出F#社区的骨头,请让微软知道他们为F#UWP应用程序支持支持 这里.

您可以找到此博客文章的整个示例代码 GitHub..

Updated: