なつねこメモ

主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ 書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。

UWP の GridView でいい感じにコンテンツを配置したい

UWP の GridView でのお話。

いい感じってどんな感じっていう話なんだけれども、文字で書くとすれば、
「ウィンドウの幅によって、水平方向コンテンツ数と幅がちゃんと変わってくれる」
みたいな感じ。

画像で表すと、例によって「ストア」や「フォト」アプリのあれです。

f:id:MikazukiFuyuno:20160626222941p:plain:w400

リサイズしてみると、個々のサイズと水平方向の個数がいい感じに変わっています。
今作ってるアプリがいわゆる画像ビューワーなのですが、これいいなーと思ったので
似たようなものを実装してみました。

添付プロパティ

public static class AssumeSize
{
    public static readonly DependencyProperty PageTokenProperty =
        DependencyProperty.RegisterAttached("AssumeSize", typeof(int), typeof(AssumeSize), new PropertyMetadata(-1));

    public static int GetAssumeSize(DependencyObject obj) => (int) obj.GetValue(PageTokenProperty);

    public static void SetAssumeSize(DependencyObject obj, int value) => obj.SetValue(PageTokenProperty, value);
}

ビヘイビア

internal class GridViewEuqalitySizeBehavior : Behavior<ItemsWrapGrid>
{
    private void OnSizeChanged(object sender, SizeChangedEventArgs e)
    {
        var size = e.NewSize;
        var assumeSize = AssumeSize.GetAssumeSize(AssociatedObject);

        var maxColumn = Math.Floor(size.Width / assumSeize);
        var adjustedSize = assumeSize + size.Width % assumeSize / maxColumn;

        AssociatedObject.ItemHeight = adjustedSize;
        AssociatedObject.ItemWidth = adjustedSize;
    }

    #region Overrides of Behavior

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.SizeChanged += OnSizeChanged;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.SizeChanged -= OnSizeChanged;
        base.OnDetaching();
    }

    #endregion
}

最後に XAML。

<GridView ItemsSource="{x:Bind ViewModel.Collection}">
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <ItemsWrapGrid attach:AssumeSize.AssumeSize="100"
                           Orientation="Horizontal">
                <i:Interaction.Behaviors>
                    <behaviors:GridViewEuqalitySizeBehavior />
                </i:Interaction.Behaviors>
            </ItemsWrapGrid>
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Image VerticalAlignment="Center"
                       Source="{Binding ThumbnailPath}"
                       Stretch="UniformToFill" />
            </Grid>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

attach:AssumeSize.AssumeSize に指定したサイズが最低サイズ。
それをベースに、配置できる数が(上の XAML の場合)水平方向最小数になるように、
アイテムのサイズを調整します。

ということで、ではでは(ヽ ´ω`)