接著,您需要在這個練習內,完成更多使用者的互動操作機制,例如,可以透過工具列的使用,讓使用者進行資料過濾、與資料重新整理或者是進行資料分享。這些許多與裝置互動的行為,都可以透過不同的插件(Plug-ins)的使用協助您做到這些應用,而您也不再需要分別了解不同平台下要如何呼叫個平台的 API,這些全部都由 插件 幫您處理掉了。
在這個階段的練習,您將會學會底下的 Xamarin.Forms 的開發技術:
在 Xamarin.Forms 使用圖片資源
創業空間明細的地圖導航
創業空間明細的撥打電話
創業空間明細的分享內容與連結
創業空間明細的開啟網頁連結
創業空間明細的訊息對話窗
工具列之資料重新整理
工具列之資料過濾設定
資料清單之互動選擇
請先下載圖片到本機電腦上的某個目錄下
將這些圖片全選,並且拖拉到 XFCreative.Droid
專案下的 Resources
> drawable
目錄內
將這些圖片全選,並且拖拉到 XFCreative.iOS
專案下的 Resources
目錄內
將這些圖片全選,並且拖拉到 XFCreative.UWP
專案下的 Assets
目錄內
重新檢視 核心PCL XFCreative
專案內的 BusinessSpaceDetailPage.xaml
檔案,您將會看到在最前面有個 Image
項目將會用來顯示圖片,不過,在這裡使用了 OnPlatform
功能,分別指定了不同平台的圖片資源。
請在 BusinessSpaceDetailPage.xaml
檔案第 27 行,找到 的宣告,使用底下 XAML 宣告,置換這個節點的定義內容
<Image.Source>
<OnPlatform x:TypeArguments="ImageSource"
iOS="info.png"
Android="info.png"
WinPhone="Assets/info.png" />
</Image.Source>
請在使用 Android 專案來執行這次修改的應用程式,您將會到如下圖,有個 i 的圖片顯示出來
創業空間明細的工具列應用
開啟 核心PCL XFCreative
專案內 Views
資料夾的 BusinessSpaceDetailPage.xaml
檔案
在 </ContentPage.Resources>
(第18行) 宣告之後,加入底下程式碼
<ContentPage.ToolbarItems>
<ToolbarItem Command="{Binding 查看地圖Command}" Text="查看地圖" Order="Secondary" Priority="0" />
<ToolbarItem Command="{Binding 撥打電話Command}" Text="撥打電話" Order="Secondary" Priority="0" />
<ToolbarItem Command="{Binding 發送簡訊Command}" Text="發送簡訊" Order="Secondary" Priority="0" />
<ToolbarItem Command="{Binding 發送電子郵件Command}" Text="發送電子郵件" Order="Secondary" Priority="0" />
<ToolbarItem Command="{Binding 分享內容Command}" Text="分享內容" Order="Secondary" Priority="0" />
<ToolbarItem Command="{Binding 分享連結Command}" Text="分享連結" Order="Secondary" Priority="0" />
<ToolbarItem Command="{Binding 查看官網Command}" Text="查看官網" Order="Secondary" Priority="0" />
</ContentPage.ToolbarItems>
上面 XAML 宣告了七個工具列項目,可以讓使用者針對這個頁面內容,進行不同動作的操作。
開啟 核心PCL XFCreative
專案內 ViewModels
資料夾的 BusinessSpaceDetailPageViewModel.cs
檔案,並且以底下程式碼置換這個檔案內容。
在建構式內,使用 Prism Unity 注入的 IPageDialogService 實作物件,這個物件可以提供一個對話窗機制,例如,這行指令,將會執行出如下圖結果
await _dialogService.DisplayAlert("抱歉", $"此功能尚未建置", "確定");
在建構式內,產生了許多 DelegateCommand
物件,這些物件將會綁定到檢視內的ContentPage.ToolbarItems
裡面的各個工具列的宣告。
當取得了某個 GPS 座標點,想要顯示外部地圖程式,導航到這個座標點,可以使用底下程式碼。
var success = await CrossExternalMaps.Current.NavigateTo(創業空間明細.創業空間名稱, fooLat, fooLon, Plugin.ExternalMaps.Abstractions.NavigationType.Default);
想要使用裝置撥打電話,可以使用底下程式碼
phoneCallTask.MakePhoneCall(創業空間明細.連絡電話);
要分享某段文字內容,也是相當容易的,使用底下程式碼來執行,此時,手機將會顯示並且請您選擇要分享的應用程式,選擇之後,就可以把這段文字分享出去。
await CrossShare.Current.Share(message, title);
要分享URL連結,也是相當容易的,使用底下程式碼來執行,此時,手機將會顯示並且請您選擇要分享的應用程式,選擇之後,就可以把URL連結分享出去。
await CrossShare.Current.ShareLink(url, message, title);
想要發送電子郵件,您可以參考下面程式碼 發送電子郵件()
方法內的註解程式碼
想要發送簡訊,您可以參考下面程式碼 發送簡訊()
方法內的註解程式碼
當取得一個網址,想要使用外部瀏覽器開啟這個網址,可以使用底下程式碼
await CrossShare.Current.OpenBrowser(創業空間明細.官方網站);
上述的許多功能都可以正常使用,這是因為您一開建立專案的時候,您有加入許多 NuGet 套件或者插件,而在這個檢視模型的程式碼內,就可以直接呼叫這些套件方法;此時,您只管需要呼叫這些功能,至於每個平台的專屬特性與功能,套件與插件會幫您處理掉這些繁雜問題。
BusinessSpaceDetailPageViewModel.cs
using Newtonsoft.Json;
using Plugin.ExternalMaps;
using Plugin.Messaging;
using Plugin.Share;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using Prism.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using XFCreative.Models;
using XFCreative.Services;
namespace XFCreative.ViewModels
{
public class BusinessSpaceDetailPageViewModel : BindableBase, INavigationAware
{
private readonly INavigationService _navigationService;
public readonly IPageDialogService _dialogService;
public DelegateCommand 查看空間資訊Command { get; set; }
public DelegateCommand 查看價格方案Command { get; set; }
public DelegateCommand 查看地圖Command { get; set; }
public DelegateCommand 撥打電話Command { get; set; }
public DelegateCommand 發送簡訊Command { get; set; }
public DelegateCommand 發送電子郵件Command { get; set; }
public DelegateCommand 分享內容Command { get; set; }
public DelegateCommand 分享連結Command { get; set; }
public DelegateCommand 查看官網Command { get; set; }
private 創業空間明細 _創業空間明細;
public 創業空間明細 創業空間明細
{
get { return _創業空間明細; }
set { SetProperty(ref _創業空間明細, value); }
}
private string _title;
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public BusinessSpaceDetailPageViewModel(INavigationService navigationService, IPageDialogService dialogService)
{
// 取得頁面導航的實作
_navigationService = navigationService;
_dialogService = dialogService;
查看空間資訊Command = new DelegateCommand(查看空間資訊);
查看價格方案Command = new DelegateCommand(查看價格方案);
查看地圖Command = new DelegateCommand(查看地圖);
撥打電話Command = new DelegateCommand(撥打電話);
發送簡訊Command = new DelegateCommand(發送簡訊);
發送電子郵件Command = new DelegateCommand(發送電子郵件);
分享內容Command = new DelegateCommand(分享內容);
分享連結Command = new DelegateCommand(分享連結);
查看官網Command = new DelegateCommand(查看官網);
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
if (parameters.ContainsKey("創業空間Selected"))
{
var foo創業空間Selected = parameters["創業空間Selected"] as 創業空間NodeViewModel;
系統初始化(foo創業空間Selected);
}
}
public void 系統初始化(創業空間NodeViewModel 創業空間NodeViewModel)
{
var fooItem = GlobalData.創業空間Repository.Items.FirstOrDefault(x => x.創業空間名稱 == 創業空間NodeViewModel.創業空間名稱);
if (fooItem != null)
{
創業空間明細 = new 創業空間明細()
{
創業空間名稱 = fooItem.創業空間名稱,
使用坪數 = fooItem.使用坪數,
使用時間 = fooItem.使用時間,
修改時間 = fooItem.修改時間,
備註 = fooItem.備註,
價格方案 = fooItem.價格方案,
創業空間類型 = fooItem.創業空間類型,
地址 = fooItem.地址,
官方網站 = fooItem.官方網站,
座標經度 = fooItem.座標經度,
座標緯度 = fooItem.座標緯度,
建物現況 = fooItem.建物現況,
建立時間 = fooItem.建立時間,
建築類型 = fooItem.建築類型,
建造材質 = fooItem.建造材質,
所屬單位 = fooItem.所屬單位,
招募團隊類型 = fooItem.招募團隊類型,
樓別樓高 = fooItem.樓別樓高,
標籤 = fooItem.標籤,
空間主照片 = fooItem.空間主照片,
空間是否出租 = fooItem.空間是否出租,
空間資訊 = fooItem.空間資訊,
縣市區域 = fooItem.縣市區域,
聯絡email = fooItem.聯絡email,
聯絡人 = fooItem.聯絡人,
詳細照片 = fooItem.詳細照片,
連絡電話 = fooItem.連絡電話,
進駐使用人數 = fooItem.進駐使用人數,
};
}
}
private async void 查看空間資訊()
{
var fooNavigationParameters = new NavigationParameters();
var fooItem = new 網頁資料NodeViewModel()
{
標題名稱 = "空間資訊",
網頁內容 = 創業空間明細.空間資訊,
};
fooNavigationParameters.Add("網頁資料NodeViewModel", fooItem);
await _navigationService.Navigate("WebView更多資訊Page", fooNavigationParameters);
}
private async void 查看價格方案()
{
var fooNavigationParameters = new NavigationParameters();
var fooItem = new 網頁資料NodeViewModel()
{
標題名稱 = "價格方案",
網頁內容 = 創業空間明細.價格方案,
};
fooNavigationParameters.Add("網頁資料NodeViewModel", fooItem);
await _navigationService.Navigate("WebView更多資訊Page", fooNavigationParameters);
}
private async void 查看地圖()
{
if (string.IsNullOrEmpty(創業空間明細.座標經度) == false && string.IsNullOrEmpty(創業空間明細.座標緯度) == false)
{
var fooLat = Convert.ToDouble(創業空間明細.座標緯度);
var fooLon = Convert.ToDouble(創業空間明細.座標經度);
var success = await CrossExternalMaps.Current.NavigateTo(創業空間明細.創業空間名稱, fooLat, fooLon, Plugin.ExternalMaps.Abstractions.NavigationType.Default);
}
}
private void 撥打電話()
{
if (string.IsNullOrEmpty(創業空間明細.連絡電話) == false)
{
// Make Phone Call
var phoneCallTask = MessagingPlugin.PhoneDialer;
if (phoneCallTask.CanMakePhoneCall)
phoneCallTask.MakePhoneCall(創業空間明細.連絡電話);
}
}
private async void 分享內容()
{
if (string.IsNullOrEmpty(創業空間明細.官方網站) == false)
{
var title = "我找到一個好地方";
var message = 創業空間明細.創業空間名稱;
// Share message and an optional title.
await CrossShare.Current.Share(message, title);
}
}
private async void 分享連結()
{
if (string.IsNullOrEmpty(創業空間明細.官方網站) == false)
{
var title = "我找到一個好地方";
var message = 創業空間明細.創業空間名稱;
var url = 創業空間明細.官方網站;
// Share a link and an optional title and message.
await CrossShare.Current.ShareLink(url, message, title);
}
}
private async void 發送電子郵件()
{
await _dialogService.DisplayAlert("抱歉", $"此功能尚未建置", "確定");
//var emailTask = MessagingPlugin.EmailMessenger;
//if (emailTask.CanSendEmail)
//{
// // Send simple e-mail to single receiver without attachments, CC, or BCC.
// emailTask.SendEmail("plugins@xamarin.com", "Xamarin Messaging Plugin", "Hello from your friends at Xamarin!");
// // Send a more complex email with the EmailMessageBuilder fluent interface.
// var email = new EmailMessageBuilder()
// .To("plugins@xamarin.com")
// .Cc("plugins.cc@xamarin.com")
// .Bcc(new[] { "plugins.bcc@xamarin.com", "plugins.bcc2@xamarin.com" })
// .Subject("Xamarin Messaging Plugin")
// .Body("Hello from your friends at Xamarin!")
// .Build();
// emailTask.SendEmail(email);
//}
}
private async void 發送簡訊()
{
await _dialogService.DisplayAlert("抱歉", $"此功能尚未建置", "確定");
//var smsMessenger = MessagingPlugin.SmsMessenger;
//if (smsMessenger.CanSendSms)
// smsMessenger.SendSms("+272193343499", "Hello from your friends at Xamarin!");
}
private async void 查看官網()
{
if (string.IsNullOrEmpty(創業空間明細.官方網站) == false)
{
await CrossShare.Current.OpenBrowser(創業空間明細.官方網站);
}
}
}
}
工具列之資料重新整理
開啟 核心PCL XFCreative
專案內 Views
資料夾的 BusinessSpacePage.xaml
檔案
在 <Grid
項目前 (第11行),加入底下 XAML 程式碼宣告
上述新增加的 XAML 宣告,加入了 ContentPage.ToolbarItems
項目 (Element),也就是可以在 ContentPage 的上方顯示這個新定義的工具列項目。
BusinessSpacePage.xaml
<ContentPage.ToolbarItems>
<ToolbarItem
Command="{Binding 搜尋Command}"
Text="搜尋"
Order="Primary"
Priority="0">
<ToolbarItem.Icon>
<OnPlatform x:TypeArguments="FileImageSource"
iOS="search.png"
Android="search.png"
WinPhone="Assets/search.png" />
</ToolbarItem.Icon>
</ToolbarItem>
<ToolbarItem
Command="{Binding RefreshDataCommand}"
Text="重新整理"
Order="Primary"
Priority="0">
<ToolbarItem.Icon>
<OnPlatform x:TypeArguments="FileImageSource"
iOS="refresh.png"
Android="refresh.png"
WinPhone="Assets/refresh.png" />
</ToolbarItem.Icon>
</ToolbarItem>
</ContentPage.ToolbarItems>
請找到 <ViewCell>
宣告,在這個項目之後,加入底下 XAML 宣告,這將定義了當使用者長按了某個清單項目,就會彈出這兩個新定義的功能表清單,如下圖所示
<ViewCell.ContextActions>
<MenuItem
Command="{Binding 查看地圖Command}"
CommandParameter="{Binding .}"
Text="查看地圖" />
<MenuItem
Command="{Binding 查看官網Command}"
CommandParameter="{Binding .}"
Text="查看官網" IsDestructive="True" />
</ViewCell.ContextActions>
開啟 核心PCL XFCreative
專案內 ViewModels
資料夾的 BusinessSpacePageViewModel.cs
檔案
將底下程式碼置換掉這個檔案內容
在建構式內增加了兩個 DelegateCommand
物件,用來綁定上方工具列的 Command 屬性。
RefreshData() 命令方法則是會切換到應用程式一開始啟動的頁面,也就是要重新抓取網路上最新的開放資料;而在 Navigate 的第一個參數使用的絕對位置標示 "/MainPage" ,這表示當切換到新的葉面之後,導航堆疊內的所有項目都要清空。
搜尋() 命令方法將會切換到另外一個頁面,設定要過濾的條件,這部分會在下一小節實作出來。
BusinessSpacePageViewModel.cs
using Newtonsoft.Json;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using XFCreative.Models;
using XFCreative.Services;
using System.Linq;
using Plugin.Share;
using Plugin.ExternalMaps;
namespace XFCreative.ViewModels
{
public class BusinessSpacePageViewModel : BindableBase, INavigationAware
{
private readonly INavigationService _navigationService;
private readonly IEventAggregator _eventAggregator;
public DelegateCommand RefreshDataCommand { get; set; }
public DelegateCommand 搜尋Command { get; set; }
public DelegateCommand 創業空間ItemSelectedCommand { get; set; }
#region 創業空間NodeViewModel 清單
private ObservableCollection<創業空間NodeViewModel> _創業空間Nodes = new ObservableCollection<創業空間NodeViewModel>();
public ObservableCollection<創業空間NodeViewModel> 創業空間Nodes
{
get { return this._創業空間Nodes; }
set { this.SetProperty(ref this._創業空間Nodes, value); }
}
#endregion
#region 創業空間Selected
public 創業空間NodeViewModel 創業空間Selected { get; set; }
#endregion
public Action 回到ListView最前面;
private string _title;
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public BusinessSpacePageViewModel(INavigationService navigationService, IEventAggregator eventAggregator)
{
// 取得頁面導航的實作
_navigationService = navigationService;
_eventAggregator = eventAggregator;
RefreshDataCommand = new DelegateCommand(RefreshData);
搜尋Command = new DelegateCommand(搜尋);
創業空間ItemSelectedCommand = new DelegateCommand(創業空間ItemSelected);
_eventAggregator.GetEvent<需要篩選資料Event>().Subscribe(需要篩選資料HandleEvent);
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
if (parameters.ContainsKey("title"))
Title = (string)parameters["title"] + " ...";
if (parameters.ContainsKey("City"))
{
var foo = (string)parameters["City"];
if (foo == "All")
{
系統初始化();
}
}
}
public void 系統初始化()
{
創業空間Nodes.Clear();
var foo創業空間s = GlobalData.創業空間Repository.Items;
foreach (var item in foo創業空間s)
{
var fooItem = new 創業空間NodeViewModel()
{
縣市區域 = item.縣市區域,
使用坪數 = item.使用坪數,
創業空間名稱 = item.創業空間名稱,
地址 = item.地址,
空間主照片 = item.空間主照片.Replace("https", "http")
};
創業空間Nodes.Add(fooItem);
}
}
private async void RefreshData()
{
var fooNavPara = new NavigationParameters();
fooNavPara.Add("title", "使用者要求重新整理");
await _navigationService.Navigate("/MainPage", fooNavPara);
}
private async void 搜尋()
{
await _navigationService.Navigate("SelectCityPage");
}
private async void 創業空間ItemSelected()
{
var foo創業空間Selected = new NavigationParameters();
foo創業空間Selected.Add("創業空間Selected", 創業空間Selected);
await _navigationService.Navigate("BusinessSpaceDetailPage", foo創業空間Selected);
}
private void 需要篩選資料HandleEvent(string obj)
{
創業空間Nodes = new ObservableCollection<創業空間NodeViewModel>();
var fooItems = GlobalData.創業空間Repository.Items.Where(x => x.縣市區域 == obj);
foreach (var item in fooItems)
{
var fooItem = new 創業空間NodeViewModel()
{
縣市區域 = item.縣市區域,
使用坪數 = item.使用坪數,
創業空間名稱 = item.創業空間名稱,
地址 = item.地址,
空間主照片 = item.空間主照片.Replace("https", "http")
};
創業空間Nodes.Add(fooItem);
}
回到ListView最前面?.Invoke();
//if (回到ListView最前面 != null)
//{
// 回到ListView最前面();
//}
}
}
}
開啟 核心PCL XFCreative
專案內 ViewModels
資料夾的 創業空間NodeViewModel.cs
檔案
將底下程式碼置換掉這個檔案內容
創業空間NodeViewModel.cs
using Plugin.ExternalMaps;
using Plugin.Share;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XFCreative.Services;
namespace XFCreative.ViewModels
{
public class 創業空間NodeViewModel : BindableBase
{
public DelegateCommand<創業空間NodeViewModel> 查看地圖Command { get; set; }
public DelegateCommand<創業空間NodeViewModel> 查看官網Command { get; set; }
#region 縣市區域
private string _縣市區域;
public string 縣市區域
{
get { return _縣市區域; }
set { SetProperty(ref _縣市區域, value); }
}
#endregion
#region 創業空間名稱
private string _創業空間名稱;
public string 創業空間名稱
{
get { return _創業空間名稱; }
set { SetProperty(ref _創業空間名稱, value); }
}
#endregion
#region 空間主照片
private string _空間主照片;
public string 空間主照片
{
get { return _空間主照片; }
set { SetProperty(ref _空間主照片, value); }
}
#endregion
#region 使用坪數
private string _使用坪數;
public string 使用坪數
{
get { return _使用坪數; }
set { SetProperty(ref _使用坪數, value); }
}
#endregion
#region 地址
private string _地址;
public string 地址
{
get { return _地址; }
set { SetProperty(ref _地址, value); }
}
#endregion
public 創業空間NodeViewModel()
{
查看地圖Command = new DelegateCommand<創業空間NodeViewModel>(查看地圖);
查看官網Command = new DelegateCommand<創業空間NodeViewModel>(查看官網);
}
private async void 查看官網(創業空間NodeViewModel obj)
{
var 創業空間明細 = GlobalData.創業空間Repository.Items.FirstOrDefault(x => x.創業空間名稱 == obj.創業空間名稱);
if (創業空間明細 != null)
{
if (string.IsNullOrEmpty(創業空間明細.官方網站) == false)
{
await CrossShare.Current.OpenBrowser(創業空間明細.官方網站);
}
}
}
private async void 查看地圖(創業空間NodeViewModel obj)
{
var 創業空間明細 = GlobalData.創業空間Repository.Items.FirstOrDefault(x => x.創業空間名稱 == obj.創業空間名稱);
if (創業空間明細 != null)
{
if (string.IsNullOrEmpty(創業空間明細.座標經度) == false && string.IsNullOrEmpty(創業空間明細.座標緯度) == false)
{
var fooLat = Convert.ToDouble(創業空間明細.座標緯度);
var fooLon = Convert.ToDouble(創業空間明細.座標經度);
var success = await CrossExternalMaps.Current.NavigateTo(創業空間明細.創業空間名稱, fooLat, fooLon, Plugin.ExternalMaps.Abstractions.NavigationType.Default);
}
}
}
}
}
工具列之資料過濾設定
最後,將要來處理過濾資料的需求,這部分除了需要建立一個檢視,讓使用者選擇過濾資料之外,還需要在這個過濾條件檢視出現之後,而使用者選擇完成之後,可以讓主清單畫面可以根據剛剛設定的條件,過濾顯示最新的清單項目;在這裡,您將會使用 Prism 提供的 IEventAggregator。
IEventAggregator 介面的實作物件所提供的功能,與 Xamarin.Forms 提供的訊息中心(MessageCenter) 類似,不過,IEventAggregator使用了弱參考(Weak Reference);使用這樣的機制的好處就是,當您訂閱一個事件之後,您不需要解除訂閱,且也不會造成記憶體洩漏(Memory Leak) 的問題。
不過,在使用 IEventAggregator 之前,需要定義一個事件專屬類別,用來區別不同的事件。
建立 事件專屬類別
在核心PCL XFCreative
專案內,使用滑鼠右鍵點選 Services
資料夾,接著,選擇 加入
> 類別
在 加入新項目 - XFCreative
對話窗中,點選 Visual C#
> 類別
在底下名稱欄位內,輸入 需要篩選資料Event
,接著,點選 新增
按鈕
使用底下程式碼替換掉剛剛產生的檔案內容
您所自訂的類別,必須要繼承 PubSubEvent 類別,其中,型別泛型的部分,則是定義要傳送的資料類型。
需要篩選資料Event.cs
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace XFCreative.Services
{
public class 需要篩選資料Event : PubSubEvent<string>
{
}
}
建立篩選過濾條件頁面檢視與檢視模型
篩選過濾條件頁面 View
在核心PCL XFCreative
專案內,使用滑鼠右鍵點選 Views
資料夾,接著,選擇 加入
> 新增項目
在 加入新項目 - XFCreative
對話窗中,點選 Visual C#
> Prism
> Prism ContentPage (Forms)
在底下名稱欄位內,輸入 SelectCityPage
,接著,點選 新增
按鈕
使用底下程式碼替換掉剛剛產生的檔案內容
SelectCityPage.xaml
- 在這裡的根項目 (Root Element) 使用的是
ContentPage
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:behaviors="clr-namespace:Behaviors;assembly=Behaviors"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
Title="請選擇要篩選的縣市"
x:Class="XFCreative.Views.SelectCityPage">
<Grid
HorizontalOptions="Fill" VerticalOptions="Fill"
>
<ListView
x:Name="listview所有縣市"
ItemsSource="{Binding 所有縣市, Mode=TwoWay}"
SelectedItem="{Binding 所有縣市Selected, Mode=TwoWay}"
CachingStrategy="RecycleElement"
>
<ListView.Behaviors>
<behaviors:EventHandlerBehavior EventName="ItemTapped">
<behaviors:InvokeCommandAction Command="{Binding 所有縣市ItemSelectedCommand}" />
</behaviors:EventHandlerBehavior>
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid
VerticalOptions="Center"
>
<Label
Text ="{Binding 縣市}"
Margin="10,5"
FontSize="22"
HorizontalOptions="Start" VerticalOptions="Center"
LineBreakMode="WordWrap"
/>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</ContentPage>
篩選過濾條件頁面 ViewModel
在核心PCL XFCreative
專案內,使用滑鼠右鍵點選 ViewModels
資料夾,接著,選擇 加入
> 類別
在 加入新項目 - XFCreative
對話窗中,點選 Visual C#
> 類別
在底下名稱欄位內,輸入 SelectCityPageViewModel
,接著,點選 新增
按鈕
使用底下程式碼替換掉剛剛產生的檔案內容
這裡要回傳使用者選擇過濾條件的值,是透過了 Prism 的 IEventAggregator 介面,不過,您也可以在呼叫 _navigationService.GoBack
方法的時候,傳入一個 NavigationParameters
物件,這樣,就可以在原先呼叫端的頁面的 OnNavigatedTo
事件方法中,接收到這個選擇過濾的條件值。
var fooPara = new NavigationParameters();
fooPara.Add("City", "AllXXX");
_navigationService.GoBack(fooPara);
SelectCityPageViewModel.cs
using Newtonsoft.Json;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using XFCreative.Models;
using XFCreative.Services;
namespace XFCreative.ViewModels
{
public class SelectCityPageViewModel : BindableBase, INavigationAware
{
private readonly INavigationService _navigationService;
private readonly IEventAggregator _eventAggregator;
#region 所有縣市 清單
private ObservableCollection<縣市節點ViewModel> _所有縣市 = new ObservableCollection<縣市節點ViewModel>();
public ObservableCollection<縣市節點ViewModel> 所有縣市
{
get { return this._所有縣市; }
set { this.SetProperty(ref this._所有縣市, value); }
}
#endregion
public DelegateCommand 所有縣市ItemSelectedCommand { get; set; }
public 縣市節點ViewModel 所有縣市Selected { get; set; }
public SelectCityPageViewModel(INavigationService navigationService, IEventAggregator eventAggregator)
{
// 取得頁面導航的實作
_navigationService = navigationService;
_eventAggregator = eventAggregator;
所有縣市ItemSelectedCommand = new DelegateCommand(所有縣市ItemSelected);
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public async void OnNavigatedTo(NavigationParameters parameters)
{
await 系統初始化();
}
public async Task 系統初始化()
{
所有縣市.Clear();
var fooItems = GlobalData.創業空間Repository.Items.Select(x => x.縣市區域).Distinct().OrderByDescending(x => x);
foreach (var item in fooItems)
{
var fooItem = new 縣市節點ViewModel
{
縣市 = item,
};
所有縣市.Add(fooItem);
}
}
private void 所有縣市ItemSelected()
{
_eventAggregator.GetEvent<需要篩選資料Event>().Publish(所有縣市Selected.縣市);
_navigationService.GoBack();
}
}
}
建立 縣市節點ViewModel ViewModel
在核心PCL XFCreative
專案內,使用滑鼠右鍵點選 ViewModels
資料夾,接著,選擇 加入
> 類別
在 加入新項目 - XFCreative
對話窗中,點選 Visual C#
> 類別
在底下名稱欄位內,輸入 縣市節點ViewModel
,接著,點選 新增
按鈕
使用底下程式碼替換掉剛剛產生的檔案內容
縣市節點ViewModel.cs
using Prism.Mvvm;
namespace XFCreative.ViewModels
{
public class 縣市節點ViewModel : BindableBase
{
#region 縣市
private string _縣市;
public string 縣市
{
get { return _縣市; }
set { SetProperty(ref _縣市, value); }
}
#endregion
}
}
顯示創意空間清單的檢視模型
創業空間項目的詳細頁面 ViewModel
在核心PCL XFCreative
專案內,在 ViewModels
資料夾,開啟 BusinessSpacePageViewModel.cs
使用底下程式碼替換掉剛剛產生的檔案內容
在建構式哩,透過 Prism Unity 容器,注入了一個實作的 IEventAggregator
物件,讓您可以透過他來使用非同步且若參考的事件通知機制。而在建構式的後面,使用了程式碼 _eventAggregator.GetEvent<需要篩選資料Event>().Subscribe(需要篩選資料HandleEvent);
訂閱了這個事件,當其他的物件送出這個訊息,需要篩選資料HandleEvent
的方法,就會立刻執行。
當 需要篩選資料HandleEvent
開始執行的時候,會根據所收到的訊息參數值,過濾出所有符合條件的資料,並且顯示在螢幕上。另外,會再透過檢視(View)的 Code Behind(後製程式碼),將清單捲動到第一個項目上,這是透過了執行這個方法: 回到ListView最前面?.Invoke();
BusinessSpaceDetailPageViewModel.cs
using Newtonsoft.Json;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using XFCreative.Models;
using XFCreative.Services;
using System.Linq;
using Plugin.Share;
using Plugin.ExternalMaps;
namespace XFCreative.ViewModels
{
public class BusinessSpacePageViewModel : BindableBase, INavigationAware
{
private readonly INavigationService _navigationService;
private readonly IEventAggregator _eventAggregator;
public DelegateCommand RefreshDataCommand { get; set; }
public DelegateCommand 搜尋Command { get; set; }
public DelegateCommand 創業空間ItemSelectedCommand { get; set; }
#region 創業空間NodeViewModel 清單
private ObservableCollection<創業空間NodeViewModel> _創業空間Nodes = new ObservableCollection<創業空間NodeViewModel>();
public ObservableCollection<創業空間NodeViewModel> 創業空間Nodes
{
get { return this._創業空間Nodes; }
set { this.SetProperty(ref this._創業空間Nodes, value); }
}
#endregion
#region 創業空間Selected
public 創業空間NodeViewModel 創業空間Selected { get; set; }
#endregion
public Action 回到ListView最前面;
private string _title;
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public BusinessSpacePageViewModel(INavigationService navigationService, IEventAggregator eventAggregator)
{
// 取得頁面導航的實作
_navigationService = navigationService;
_eventAggregator = eventAggregator;
RefreshDataCommand = new DelegateCommand(RefreshData);
搜尋Command = new DelegateCommand(搜尋);
創業空間ItemSelectedCommand = new DelegateCommand(創業空間ItemSelected);
_eventAggregator.GetEvent<需要篩選資料Event>().Subscribe(需要篩選資料HandleEvent);
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
if (parameters.ContainsKey("title"))
Title = (string)parameters["title"] + " ...";
if (parameters.ContainsKey("City"))
{
var foo = (string)parameters["City"];
if (foo == "All")
{
系統初始化();
}
}
}
public void 系統初始化()
{
創業空間Nodes.Clear();
var foo創業空間s = GlobalData.創業空間Repository.Items;
foreach (var item in foo創業空間s)
{
var fooItem = new 創業空間NodeViewModel()
{
縣市區域 = item.縣市區域,
使用坪數 = item.使用坪數,
創業空間名稱 = item.創業空間名稱,
地址 = item.地址,
空間主照片 = item.空間主照片.Replace("https", "http")
};
創業空間Nodes.Add(fooItem);
}
}
private async void RefreshData()
{
var fooNavPara = new NavigationParameters();
fooNavPara.Add("title", "使用者要求重新整理");
await _navigationService.Navigate("/MainPage", fooNavPara);
}
private async void 搜尋()
{
await _navigationService.Navigate("SelectCityPage");
}
private async void 創業空間ItemSelected()
{
var foo創業空間Selected = new NavigationParameters();
foo創業空間Selected.Add("創業空間Selected", 創業空間Selected);
await _navigationService.Navigate("BusinessSpaceDetailPage", foo創業空間Selected);
}
private void 需要篩選資料HandleEvent(string obj)
{
創業空間Nodes = new ObservableCollection<創業空間NodeViewModel>();
var fooItems = GlobalData.創業空間Repository.Items.Where(x => x.縣市區域 == obj);
foreach (var item in fooItems)
{
var fooItem = new 創業空間NodeViewModel()
{
縣市區域 = item.縣市區域,
使用坪數 = item.使用坪數,
創業空間名稱 = item.創業空間名稱,
地址 = item.地址,
空間主照片 = item.空間主照片.Replace("https", "http")
};
創業空間Nodes.Add(fooItem);
}
回到ListView最前面?.Invoke();
//if (回到ListView最前面 != null)
//{
// 回到ListView最前面();
//}
}
}
}
創業空間項目的詳細頁面 View
在核心PCL XFCreative
專案內,在 ViewModels
資料夾,開啟 BusinessSpacePage.xaml.cs
使用底下程式碼替換掉剛剛產生的檔案內容
這裡會定義一個 Code Behind 的方法,回到ListView最前面Delegate
,這個方法將會捲動到回到第一個清單項目。
BusinessSpacePage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using XFCreative.ViewModels;
namespace XFCreative.Views
{
public partial class BusinessSpacePage : ContentPage
{
BusinessSpacePageViewModel BusinessSpacePageViewModel;
public BusinessSpacePage()
{
InitializeComponent();
BusinessSpacePageViewModel = this.BindingContext as BusinessSpacePageViewModel;
BusinessSpacePageViewModel.回到ListView最前面 = 回到ListView最前面Delegate;
}
private void 回到ListView最前面Delegate()
{
if (BusinessSpacePageViewModel.創業空間Nodes.Count > 0)
{
var fooItem = BusinessSpacePageViewModel.創業空間Nodes[0];
listview創業空間.ScrollTo(fooItem, ScrollToPosition.Center, false);
}
}
}
}
修改 MainPageViewModel 檢視模型
在核心PCL XFCreative
專案內的 ViewModels
資料夾,開啟 MainPageViewModel.cs
使用底下程式碼替換掉剛剛產生的檔案內容
這裡修正了,當要導航到 BusinessSpacePage
頁面,需要傳遞一個 City 名稱的參數,其參數值為 All,表示,當進入到 BusinessSpacePage
頁面後,要顯示所有的資料。
App.xaml.cs
using Newtonsoft.Json;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using XFCreative.Models;
using XFCreative.Services;
namespace XFCreative.ViewModels
{
public class MainPageViewModel : BindableBase, INavigationAware
{
private readonly INavigationService _navigationService;
private string _title;
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public MainPageViewModel(INavigationService navigationService)
{
// 取得頁面導航的實作
_navigationService = navigationService;
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public async void OnNavigatedTo(NavigationParameters parameters)
{
if (parameters.ContainsKey("title"))
Title = (string)parameters["title"] + " ...";
await 系統初始化();
var fooPara = new NavigationParameters();
fooPara.Add("City", "All");
await _navigationService.Navigate("/HomePage/BusinessSpacePage", fooPara);
}
public async Task 系統初始化()
{
await GlobalData.創業空間Repository.取得最新資料();
}
}
}
使用 Unity 容器註冊新建立的 View
在核心PCL XFCreative
專案內,開啟 App.xaml.cs
使用底下程式碼替換掉剛剛產生的檔案內容
App.xaml.cs
using Prism.Unity;
using XFCreative.Views;
namespace XFCreative
{
public partial class App : PrismApplication
{
protected override void OnInitialized()
{
InitializeComponent();
NavigationService.Navigate("MainPage?title=請稍後,正在更新資料");
}
protected override void RegisterTypes()
{
Container.RegisterTypeForNavigation<MainPage>();
Container.RegisterTypeForNavigation<HomePage>();
Container.RegisterTypeForNavigation<BusinessSpacePage>();
Container.RegisterTypeForNavigation<BusinessSpaceDetailPage>();
Container.RegisterTypeForNavigation<WebView更多資訊Page>();
Container.RegisterTypeForNavigation<SelectCityPage>();
}
}
}
執行結果
Android 執行結果
請在方案總管內,滑鼠右擊 XFCreative.Droid
專案,選擇 設定為起始專案
,接著按下 F5
開始執行。