1. 程式人生 > >走進 Prism for Xamarin.Forms

走進 Prism for Xamarin.Forms

很多 ppa arp case tail source ride ini har

一、使用環境

OS:Win 10 16273

VS:VS2017- 15.3.4

Xamarin:4.6.3.4,nuget:2.4

Android Emulator:Visual Studio for Android Emulator(相比 Android Emulator不用下載SDK,而且啟動快)

二、安裝 Prism 模塊

工具——擴展和更新——搜索 Prism Template Pack——安裝

三、開始搞起

1.先建個項目

技術分享

技術分享

2.添加頁面

Views文件夾右鍵——添加——新建項,彈出來的對話框先選中左邊的 Prism 節點

技術分享

確定後,你會發現 App.xaml.cs 文件裏註入了新建的頁面, ViewModels 文件夾下也多出了 ViewModel ,Views 新添加的文件也是和 ViewModel 綁定好的

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="SD.Xamarin.Views.LoginPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
    Title="Login"
    prism:ViewModelLocator.AutowireViewModel="True">

    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Regist" />
    </ContentPage.ToolbarItems>

    <StackLayout
        Padding="20"
        Spacing="20"
        VerticalOptions="Center">

        <Entry Placeholder="Username" Text="{Binding Username}" />
        <Entry
            IsPassword="true"
            Placeholder="Password"
            Text="{Binding Password}" />

        <Button
            BackgroundColor="#77D065"
            Command="{Binding LoginCommand}"
            Text="Login"
            TextColor="White" />
    </StackLayout>

</ContentPage>

public class LoginPageViewModel : BindableBase
    {
        private readonly INavigationService _navigationService;
        private readonly IEventAggregator _eventAggregator;
        private readonly IPageDialogService _pageDialogService;


        private string _username;

        public string Username
        {
            get { return _username; }
            set
            {
                _username = value;
                RaisePropertyChanged();
            }
        }

        private string _password;

        public string Password
        {
            get { return _password; }
            set
            {
                _password = value;
                RaisePropertyChanged();
            }
        }

        private ICommand _loginCommand;

        public ICommand LoginCommand
        {
            get { return _loginCommand ?? new DelegateCommand(Login); }
            set { _loginCommand = value; }
        }

        public LoginPageViewModel(INavigationService navigationService, IEventAggregator eventAggregator, IPageDialogService pageDialogService)
        {
            _navigationService = navigationService;
            _eventAggregator = eventAggregator;
            _pageDialogService = pageDialogService;
        }

        private async void Login()
        {
            if (!string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password))
            {
                await _navigationService.NavigateAsync(nameof(DataCabinPage));
            }
            else
            {
                await _pageDialogService.DisplayAlertAsync("Error", "Wrong Username or Password", "OK!");
            }
        }
    }

3.添加一個 Master 頁面作為主頁面

<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage
    x:Class="SD.Xamarin.Views.MasterPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:behaviors="clr-namespace:Prism.Behaviors;assembly=Prism.Forms"
    xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
    xmlns:views="clr-namespace:SD.Xamarin.Views;assembly=SD.Xamarin"
    Title="Master"
    prism:ViewModelLocator.AutowireViewModel="True">

    <MasterDetailPage.Master>
        <NavigationPage Title="Required Foo" Icon="hamburger.png">
            <x:Arguments>
                <views:DataCabinPage />
            </x:Arguments>
        </NavigationPage>
    </MasterDetailPage.Master>

</MasterDetailPage>

Master裏的子頁面

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="SD.Xamarin.Views.DataCabinPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:behaviors="clr-namespace:Prism.Behaviors;assembly=Prism.Forms"
    xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
    Title="DataCabin"
    prism:ViewModelLocator.AutowireViewModel="True">

    <ContentPage.ToolbarItems>
        <ToolbarItem Command="GoBackCommand" Text="Back" />
    </ContentPage.ToolbarItems>

    <ListView
        x:Name="listView"
        CachingStrategy="RecycleElement"
        GroupDisplayBinding="{Binding Key}"
        GroupShortNameBinding="{Binding Key}"
        IsGroupingEnabled="True"
        ItemsSource="{Binding DataCabinsGrouped}"
        SelectedItem="{Binding SelectedDataCabin}">

        <ListView.Behaviors>
            <behaviors:EventToCommandBehavior Command="{Binding ItemTappedCommand}" EventName="ItemTapped" />
        </ListView.Behaviors>

<ListView.GroupHeaderTemplate> <DataTemplate> <ViewCell> <StackLayout Orientation="Horizontal"> <Image Source="hamburger.png" /> <Label FontSize="18" Text="{Binding Key}" TextColor="DeepSkyBlue" VerticalTextAlignment="Center" /> </StackLayout> </ViewCell> </DataTemplate> </ListView.GroupHeaderTemplate> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <Label Text="{Binding Name}" TextColor="White" VerticalTextAlignment="Center" /> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage>

public class DataCabinPageViewModel : BindableBase
    {
        private readonly INavigationService _navigationService;
        private readonly IEventAggregator _eventAggregator;
        private readonly IPageDialogService _pageDialogService;

        private DataCabinModel _selectedDataCabin;

        public DataCabinModel SelectedDataCabin
        {
            get { return _selectedDataCabin; }
            set
            {
                _selectedDataCabin = value;
                RaisePropertyChanged();
            }
        }

        private ObservableCollection<DataCabinModel> _dataCabins;

        public ObservableCollection<DataCabinModel> DataCabins
        {
            get { return _dataCabins; }
            set
            {
                _dataCabins = value;
                RaisePropertyChanged();
            }
        }

        private ObservableCollection<GroupingModel<string, DataCabinModel>> _dataCabinsGrouped;

        public ObservableCollection<GroupingModel<string, DataCabinModel>> DataCabinsGrouped
        {
            get { return _dataCabinsGrouped; }
            set
            {
                _dataCabinsGrouped = value;
                RaisePropertyChanged();
            }
        }

        private ICommand _itemTappedCommand;

        public ICommand ItemTappedCommand
        {
            get { return _itemTappedCommand ?? new DelegateCommand(ItemTapped); }
            set { _itemTappedCommand = value; }
        }

        private ICommand _goBackCommand;

        public ICommand GoBackCommand
        {
            get { return _goBackCommand ?? new DelegateCommand(GoBack); }
            set { _goBackCommand = value; }
        }

        public DataCabinPageViewModel(INavigationService navigationService, IEventAggregator eventAggregator, IPageDialogService pageDialogService)
        {
            _navigationService = navigationService;
            _eventAggregator = eventAggregator;
            _pageDialogService = pageDialogService;

            DataCabins = new ObservableCollection<DataCabinModel>()
            {
                new DataCabinModel(){Id=1,Name = "T1",GroupName="G1",DisplayType= DataCabinType.Chart},
                new DataCabinModel(){Id=2,Name = "T2",GroupName="G1",DisplayType= DataCabinType.Grid},
                new DataCabinModel(){Id=3,Name = "T3",GroupName="G2",DisplayType= DataCabinType.Guage},
                new DataCabinModel(){Id=4,Name = "T4",GroupName="G2",DisplayType= DataCabinType.Map}
            };

            var grouped = from menuItem in DataCabins
                          orderby menuItem.Id
                          group menuItem by menuItem.GroupName into menuItemGroup
                          select new GroupingModel<string, DataCabinModel>(menuItemGroup.Key, menuItemGroup);

            DataCabinsGrouped = new ObservableCollection<GroupingModel<string, DataCabinModel>>(grouped);
        }

        private async void ItemTapped()
        {
            switch (SelectedDataCabin.DisplayType)
            {
                case DataCabinType.Chart:
                    await _navigationService.NavigateAsync("/Master/Navigation/" + nameof(ChartPage));
                    break;
                case DataCabinType.Grid:
                    await _navigationService.NavigateAsync("/Master/Navigation/" + nameof(GridPage));
                    break;
                case DataCabinType.Guage:
                    await _navigationService.NavigateAsync("/Master/Navigation/" + nameof(GuagePage));
                    break;
                case DataCabinType.Map:
                    await _navigationService.NavigateAsync("/Master/Navigation/" + nameof(MapPage));
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

        }

        private void GoBack()
        {
            _navigationService.NavigateAsync(nameof(DataCabinPage));
        }
    }

App.xaml

public partial class App : PrismApplication
    {
        public App(IPlatformInitializer initializer = null) 
            : base(initializer)
        { }

        protected override void OnInitialized()
        {
            InitializeComponent();

            NavigationService.NavigateAsync(nameof(LoginPage));
        }

        protected override void RegisterTypes()
        {
            Container.RegisterTypeForNavigation<NavigationPage>("Navigation");

            Container.RegisterTypeForNavigation<RegistPage>();
            Container.RegisterTypeForNavigation<LoginPage>();
            Container.RegisterTypeForNavigation<MasterPage>("Master");
            Container.RegisterTypeForNavigation<ChartPage>();
            Container.RegisterTypeForNavigation<GridPage>();
            Container.RegisterTypeForNavigation<GuagePage>();
            Container.RegisterTypeForNavigation<MapPage>();
            Container.RegisterTypeForNavigation<DataCabinPage>();
        }
    }

這是最終的 App 文件,註意其中的NavigationPage 和MasterPage 後邊都加了參數,用來導航用的,因為想要漢堡包樣式

漢堡包的圖片是從官方例子復制的,需要放到

Android:技術分享

IOS:直接 Resources 文件夾下

導航的寫法 await _navigationService.NavigateAsync("/Master/Navigation/" + nameof(ChartPage)); 這裏就是App.xaml.cs 文件裏註冊時的那個參數,本來想把前邊也寫出nameof 的方式,但是發現直接失敗了,就只能這樣了

其他的代碼都很建單,也沒寫什麽邏輯,就不貼了,大概就是這個樣子,嗯,下一步就要引入 syncfusion 的控件才行了,這樣才好看,也能有很多控件用(主要是實在不知道寫什麽業務)

動態圖

技術分享

四、模擬器

工具——Visual Studio Emulator for Android 彈出的裏邊選擇一個下載就好了,是基於Hyper-V 的,需要確定你的機器支持

技術分享

窗口——其他窗口——Xamarin.Forms Previewer 也是可以預覽的,但是用了Prism 後,App.xaml.cs 裏的構造函數變了,然後就顯示不了了~~

技術分享

五、遇到的問題

1.F5 運行後,執行了 編譯——部署,然後就停了,不能像WPF 項目一樣實時Debug ,也不知道需要配置什麽,這樣一旦出錯,就得一點點試,很不舒服

2.點擊主頁後跳轉到子頁面,再彈出漢堡包跳轉第二個,再跳轉第三個後 程序就崩潰了,也不知道為什麽

3.有時頁面的ToolbarItem 不顯示,但是放到漢堡包裏的那個就顯示,不知道怎麽搞的,

以上問題有知道的,請多指教啊

六、總結

Xamarin 整合到VS 裏後,環境配置相比剛出來時好配置好多,VS Emulator 的加入也省去了下載 Android SDK時的困難,而且還特別大,雖然VS的某些功能還是需要FQ下載。

WP已死,沒必要開發,UWP 肯定是回到桌面的 UWP 開發比較好,調試和用法更好用,而且還可以查看虛擬樹什麽的,好方便的。

CM框架也要出4.0了,到時再試試CM

七、參考例子

Prism:https://github.com/PrismLibrary/Prism-Samples-Forms

Xamarin:https://github.com/xamarin/xamarin-forms-samples

走進 Prism for Xamarin.Forms