一、使用環境
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的某些功能還是需要翻牆下載。
WP已死,沒必要開發,UWP 肯定是回到桌面的 UWP 開發比較好,調試和用法更好用,而且還可以查看虛擬樹什么的,好方便的。
CM框架也要出4.0了,到時再試試CM
七、參考例子
Prism:https://github.com/PrismLibrary/Prism-Samples-Forms
Xamarin:https://github.com/xamarin/xamarin-forms-samples
