読者です 読者をやめる 読者になる 読者になる

みかづきメモ

学習したことのメモとか、日記とか、備忘録。

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

C# UWP

UWP の GridView でのお話。

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

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

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

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

添付プロパティ

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

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

    public static void SetAssumSize(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 assumSize = AssumSize.GetAssumSize(AssociatedObject);

        var maxColumn = Math.Floor(size.Width / assumSize);
        var adjustedSize = assumSize + size.Width % assumSize / 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:AssumSize.AssumSize="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:AssumSize.AssumSize に指定したサイズが最低サイズ。
それをベースに、配置できる数が(上の XAML の場合)水平方向最小数になるように、
アイテムのサイズを調整します。

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