在上一篇博文《 "[UWP]使用Popup構建UWP Picker" 》中我們簡單講述了一下使用Popup構建適用於MVVM框架下的彈窗層組件Picker的過程。但是沒有應用實例的話可能體現不出Picker相對於ContentDialog的優點在哪裡,畢竟Linus大神說過: Talk is che ...
在上一篇博文《[UWP]使用Popup構建UWP Picker》中我們簡單講述了一下使用Popup構建適用於MVVM框架下的彈窗層組件Picker的過程。但是沒有應用實例的話可能體現不出Picker相對於ContentDialog的優點在哪裡,畢竟Linus大神說過:
Talk is cheap, show me the code!
我們假定要實現這樣一個顏色選擇器:當用戶需要選擇一個顏色時,應用彈出顏色選擇器,用戶選擇完成後,點擊“確定”按鈕關閉彈窗,並且向調用方代碼返回用戶選擇的顏色值。
它的調用界面是這樣的:
編寫ColorPicker彈窗的業務邏輯代碼
上篇博文里我們講到要實現Picker功能,其ViewModel必須實現IObjectPicker介面。我在HHChaosToolkit庫中已經定義了ObjectPickerBase作為Picker的公共基類,我們的ViewModel直接繼承它就可以了。
IObjectPicker的介面定義:
public interface IObjectPicker<T>
{
event EventHandler<ObjectPickedEventArgs<T>> ObjectPicked;
event EventHandler Canceled;
}
ObjectPickerBase的定義:
public abstract class ObjectPickerBase<T> : ViewModelBase, IObjectPicker<T>
{
public event EventHandler<ObjectPickedEventArgs<T>> ObjectPicked;
public event EventHandler Canceled;
/// <summary>
/// 設置選擇的對象
/// </summary>
/// <param name="result"></param>
public void SetResult(T result)
{
ObjectPicked?.Invoke(this, new ObjectPickedEventArgs<T>(result));
}
/// <summary>
/// 取消Pick操作
/// </summary>
public void Exit()
{
Canceled?.Invoke(this, EventArgs.Empty);
}
public RelayCommand ExitCommand => new RelayCommand(Exit);
}
這裡我們編寫一個TestColorPickerViewModel作為ColorPicker彈窗界面的ViewModel,其代碼如下:
public class TestColorPickerViewModel: ObjectPickerBase<Color>
{
private Color _pickedColor;
public Color PickedColor
{
get => _pickedColor;
set => Set(ref _pickedColor, value);
}
public override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Parameter is Color color)
{
PickedColor = color;
}
base.OnNavigatedTo(e);
}
public ICommand PickColorCommand => new RelayCommand(() =>
{
SetResult(PickedColor);
});
}
其中有一個重載的方法OnNavigatedTo,這個用於接受打開彈窗時給傳遞給Picker的參數,這個屬於HHChaosToolkit類庫中MVVM導航服務的一部分功能,以後的博客我可能會拿出來單獨講一下。
我們看到,TestColorPickerViewModel的代碼邏輯非常簡單,在執行PickColorCommand後返回PickedColor作為結果。
編寫ColorPicker的UI層代碼
View層交互不多,我們新建一個Page,然後添加一個ColorPicker控制項,Color屬性綁定ViewModel的PickedColor,添加一個“確定”按鈕綁定PickColorCommand,xaml.cs文件中無需添加任何代碼,xaml代碼如下:
<Page
x:Class="HHChaosToolkit.Sample.Views.TestPages.TestColorPickerPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:HHChaosToolkit.Sample.Views.TestPages"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
DataContext="{Binding TestColorPickerViewModel, Source={StaticResource Locator}}"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid Background="White" BorderBrush="#d9ddea" BorderThickness="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Height="40" Background="#d9ddea">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock
Margin="15,0"
VerticalAlignment="Center"
FontSize="14px"
Foreground="#474261"
Text="ColorPicker" />
<Button
Grid.Column="1"
Command="{Binding ExitCommand}"
Style="{StaticResource PickerCloseButtonStyle}" />
</Grid>
<Grid Grid.Row="1" Padding="20,10">
<ColorPicker x:Name="ColorPicker" Color="{Binding PickedColor,Mode=TwoWay}"/>
</Grid>
<Grid Grid.Row="2" Padding="20">
<Button HorizontalAlignment="Center" Content="確定" Command="{Binding PickColorCommand}"/>
</Grid>
</Grid>
</Grid>
</Page>
註冊調用過程
註冊ColorPicker彈窗
我們首先要在ViewModelLocator中註冊TestColorPickerViewModel為可選取Color類型的Picker對象,代碼如下:
RegisterObjectPicker<Color, TestColorPickerViewModel, TestColorPickerPage>();
其中RegisterObjectPicker方法的源碼如下:
public void RegisterObjectPicker<T, VM, V>()
where VM : ObjectPickerBase<T>
{
SimpleIoc.Default.Register<VM>();
ObjectPickerService.Configure(typeof(T).FullName, typeof(VM).FullName, typeof(V));
}
這段代碼目的是在ObjectPickerService中註冊TestColorPickerViewModel為可選取Color類型的Picker對象,這樣我們之後的調用可以直接通過ObjectPickerService來進行。
必須要說明的是ObjectPickerService可以為同一類型註冊多個Picker對象,類似於Windows系統中可安裝多個視頻播放器,調用時指定使用哪個播放器即可。
調用ColorPicker彈窗
在ObjectPickerService中註冊過後,我們即可在任意需要選取顏色的地方使用我們的ColorPicker彈窗,最簡單的調用方法時這樣的:
var pickerService = ServiceLocator.Current.GetInstance<ObjectPickerService>();
var ret = await pickerService.PickSingleObjectAsync<Color>(typeof(TestColorPickerViewModel)
.FullName, PickedColor);
if (!ret.Canceled)
{
PickedColor = ret.Result;
var toast = new Toast($"You picked a new color!({ret.Result})");
toast.Show();
}
當然我們也可以自定義彈出界面的位置、背景、動畫及點擊空白區域退出等選項。如果需要這樣自定義的話,我們要用到PickerOpenOption這個類,這個類用來設置Picker彈出時的自定義配置項,例如:
var pickerService = ServiceLocator.Current.GetInstance<ObjectPickerService>();
var openOption = new PickerOpenOption
{
EnableTapBlackAreaExit = true,
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Right,
Background = new AcrylicBrush
{
TintOpacity = 0.1
},
Transitions = new TransitionCollection
{
new EdgeUIThemeTransition
{
Edge = EdgeTransitionLocation.Right
}
}
};
var ret = await pickerService.PickSingleObjectAsync<Color>(typeof(TestColorPickerViewModel)
.FullName, PickedColor, openOption);
if (!ret.Canceled)
{
PickedColor = ret.Result;
var toast = new Toast($"You picked a new color!({ret.Result})");
toast.Show();
}
它的呈現效果是這樣的:
結尾
這篇博文里我給大家講解瞭如何使用Picker來構建一個顏色選擇器彈窗,這隻是一個小例子,Picker有非常多的使用場景,例如:
- 文本輸入彈窗(註冊類型為string);
- 普通自定義Dialog界面(統一註冊類型為bool即可);
- 圖片編輯彈窗(註冊類型為文件或者圖片);
- ...
最後,完整項目代碼鏈接在這裡:GitHub鏈接點這裡,歡迎大家使用,或者提出意見!
本篇博客到此結束!謝謝大家!