SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

UWP Community Toolkit 1.4.1を使ってみた

UWP Community ToolkitのV1.4.1がリリースされてました。
https://github.com/Microsoft/UWPCommunityToolkit/releases/tag/1.4.0
https://github.com/Microsoft/UWPCommunityToolkit/releases/tag/1.4.1

ということで今回も、個人的にいいなと思った点をまとめておきます。

新規コントロール

Carousel

一昔前によく見かけた感じの、カルーセル表示をするコントロールが追加されてました。

ItemsControl派生のコントロールとなっているので、ItemsSourceプロパティに表示したい要素を設定すれば、
こんな風に表示することができます。

f:id:minami_SC:20170421234658p:plain

MainPage.xaml

        <controls:Carousel ItemDepth="200" ItemsSource="{x:Bind ImageList}" ItemRotationY="45" ItemMargin="-30">
            <controls:Carousel.ItemTemplate>
                <DataTemplate>
                    <Image Width="200"
                           Height="200"
                           Source="{Binding}"
                           Stretch="Uniform" />
                </DataTemplate>
            </controls:Carousel.ItemTemplate>
        </controls:Carousel>

MainPage.xaml.cs

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            this.ImageList = new List<string>()
            {
                "Images/1.JPG",
                "Images/2.JPG",
                "Images/3.JPG",
                "Images/4.JPG",
                "Images/5.JPG",
                "Images/6.JPG",
            };
        }

        public IList<string> ImageList { get; set; }
    }
プロパティなど
プロパティ名 内容
ItemsSource object ルーセルに表示する要素を設定
ItemTemplate DataTemplate 各要素を表示するためのテンプレートを設定
Orientation Orientation 要素が並ぶ向きを設定
ItemDepth int 選択状態の要素と、それ以外の要素の距離を設定。これを大きな値にすると、非選択状態の要素がより奥に引っ込む感じになります。
ItemMargin int 各要素同士の感覚を設定します
ItemRotationX
ItemRotationY
ItemRotationZ
int 非選択状態の要素を、それぞれの軸方向にどれだけ傾けるかを設定します。
InvertPositive bool このプロパティをfalseにすると、非選択状態の要素がすべて同じ方向に傾くようになります。デフォルトのtrueの状態だと、左右で反転して傾くようになります。
EasingFunction EasingFunctionBase 選択項目が切り替わる際のアニメーションのイージングを設定
注意事項

↓を見たところ、ItemDepthプロパティを明示的にセットしておかないと、例外を吐いてアプリが落ちてしまいます。
https://github.com/Microsoft/UWPCommunityToolkit/issues/1090

そのうち修正されるとは思いますが、しばらくの間はこのプロパティには何らかの値を必ずセットして使うようにしましょう。

Developer Tools

デバッグ用途で役に立ちそうなコントロールが2つ追加されています。

  • FocusTracker
  • AlignmentGrid

これらのコントロールを使う場合は、NugetからMicrosoft.Toolkit.Uwp.DeveloperToolsをインストールしておきましょう。

FocusTracker

こちらは、現在フォーカスを持っている要素の情報を表示してくれるコントロールです。

f:id:minami_SC:20170421234718p:plain

こんな風に、フォーカスが当たっているコントロールの名前などの情報が表示されます。
使いどころがあまりわからないですが・・・

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition Width="300" />
        </Grid.ColumnDefinitions>
        <developerTools:FocusTracker Grid.Column="1" IsActive="True" />
        <Button x:Name="button1"
                Margin="10,10,0,0"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Content="Button" />
        <TextBox Margin="10,47,0,0"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Top"
                 Text="TextBox"
                 TextWrapping="Wrap" />
        <RadioButton Margin="10,78,0,0"
                     HorizontalAlignment="Left"
                     VerticalAlignment="Top"
                     Content="RadioButton" />
    </Grid>
AlignmentGrid

こんな風に、一定間隔のグリッドが表示されます。
レイアウトが乱れていないかチェックするのに役立つかと思います。

f:id:minami_SC:20170421234726p:plain

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <developerTools:AlignmentGrid HorizontalStep="20"
                                      LineBrush="Black"
                                      Opacity="0.2"
                                      VerticalStep="20" />
        <Button Margin="20,20,0,0"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Content="Button" />
        <TextBlock Margin="40,80,0,0"
                   HorizontalAlignment="Left"
                   VerticalAlignment="Top"
                   Text="TextBlock"
                   TextWrapping="Wrap" />
    </Grid>
プロパティ名 内容
Opacity double コントロール全体の不透明度
LineBrush Brush グリッド線描画に利用するブラシを設定
HorizontalStep double 水平方向のグリッド間隔
VerticalStep double 垂直方向のグリッド間隔

既存コントロールの改善点

MarkdownTextBlock

マークダウンの各種構文への対応改善

V1.3では、テーブル構文が正しく表示されない、、、など色々とマークダウンの表示に問題がありましたが、色々と修正されています。

テーブル表示だけでなく、GitHubのマークダウンのように```で括ってコードブロックを定義できるようになったりしてます。

ただし、言語を指定してのシンタックスハイライトなどは対応してないみたい。

f:id:minami_SC:20170421234734p:plain

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <TextBox x:Name="txtMarkdownSource" Margin="5"
                 AcceptsReturn="True" />

        <ScrollViewer Grid.Column="1"
                      Margin="5"
                      BorderBrush="{ThemeResource AppBarBorderThemeBrush}"
                      BorderThickness="2"
                      HorizontalScrollBarVisibility="Disabled"
                      VerticalScrollBarVisibility="Auto">
            <controls:MarkdownTextBlock Margin="6"
                                        Foreground="Black"
                                        Text="{Binding Text, ElementName=txtMarkdownSource}" />
        </ScrollViewer>
    </Grid>

MasterDetailView

MasterとDetailそれぞれに別々のCommandBarを付けられるようになりました。

f:id:minami_SC:20170421234746p:plain

プロパティ名 内容
MasterCommandBar CommandBar Master側のCommandBarを設定
DetailsCommandBar CommandBar Detail側のCommandBarを設定

MainPage.xaml

    <Page.Resources>
        <DataTemplate x:Key="ListTemplate" x:DataType="local:MenuItem">
            <StackPanel Margin="0,8">
                <TextBlock Style="{ThemeResource SubtitleTextBlockStyle}" Text="{x:Bind Title}" />
                <TextBlock Text="{x:Bind ImagePath}" />
            </StackPanel>
        </DataTemplate>
        <DataTemplate x:Key="DetailsTemplate" x:DataType="local:MenuItem">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition />
                </Grid.RowDefinitions>
                <RelativePanel Margin="5">
                    <Ellipse x:Name="FromEllipse" Width="50" Height="50" Fill="Gray" />
                    <TextBlock Margin="12,-6,0,0"
                               RelativePanel.RightOf="FromEllipse"
                               Style="{ThemeResource SubtitleTextBlockStyle}"
                               Text="{x:Bind Title}" />
                    <TextBlock RelativePanel.Below="FromEllipse" Text="{x:Bind ImagePath}" />
                </RelativePanel>
                <Image Grid.Row="1" Margin="5"
                       Source="{x:Bind ImagePath}"
                       Stretch="Uniform" />
            </Grid>
        </DataTemplate>
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <controls:MasterDetailsView ItemsSource="{x:Bind List}"
                                    ItemTemplate="{StaticResource ListTemplate}"
                                    DetailsTemplate="{StaticResource DetailsTemplate}"
                                    MasterHeader="ヘッダー"
                                    MasterPaneWidth="200"
                                    NoSelectionContent="要素が選択されていません">
            <controls:MasterDetailsView.MasterCommandBar>
                <CommandBar ClosedDisplayMode="Minimal">
                    <CommandBar.SecondaryCommands>
                        <AppBarButton Label="Secondary1" Icon="Edit"/>
                        <AppBarButton Label="Secondary2" Icon="Edit"/>
                        <AppBarToggleButton Label="Secondary3" Icon="Edit"/>
                    </CommandBar.SecondaryCommands>
                    <!--ここに定義したものはPrimaryCommandsプロパティになる-->
                    <AppBarButton Label="Primary1" Icon="Font"/>
                    <AppBarToggleButton Label="Primary2" Icon="Edit"/>
                </CommandBar>
            </controls:MasterDetailsView.MasterCommandBar>
        </controls:MasterDetailsView>
    </Grid>

MainPage.xaml.cs

    public sealed partial class MainPage : Page
    {
        public ObservableCollection<MenuItem> List { get; set; }

        public MainPage()
        {
            this.InitializeComponent();

            this.List = new ObservableCollection<MenuItem>()
            {
                new MenuItem("Sample1", "Images/1.JPG"),
                new MenuItem("Sample2", "Images/2.JPG"),
                new MenuItem("Sample3", "Images/3.JPG"),
                new MenuItem("Sample4", "Images/4.JPG"),
                new MenuItem("Sample5", "Images/5.JPG"),
                new MenuItem("Sample6", "Images/6.JPG"),
            };
        }
    }

    public class MenuItem
    {
        public string Title { get; set; }
        public string ImagePath { get; set; }

        public MenuItem(string title, string path)
        {
            this.Title = title;
            this.ImagePath = path;
        }
    }