首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >W10新闻应用程序如何拉伸网格视图中的项目?

W10新闻应用程序如何拉伸网格视图中的项目?
EN

Stack Overflow用户
提问于 2015-09-07 18:14:54
回答 1查看 751关注 0票数 19

我正在尝试创建一个网格视图,就像Windows10中默认的新闻应用程序一样。据我所知,我必须为VariableSizedWrapGrid设置一个ItemHeight的ItemWidth。但它不会拉伸项目以适应整个网格宽度,而新闻应用程序确实可以做到这一点,如下图所示。他们如何做到这一点呢?它是一个特殊的自定义控件吗?

EN

回答 1

Stack Overflow用户

发布于 2017-01-10 03:09:58

UWP

作为我之前的回答的补充,我在这里展示了基本概念,这是一个使用问题中提到的VariableSizedWrapPanel的UWP平台的解决方案:

主要工作由

代码语言:javascript
复制
<local:MyGridView 
    ItemsSource="{Binding}" 
    ItemTemplateSelector="{StaticResource MyGridTemplateSelector}" 
    MinItemWidth="300" MaxItemWidth="600" 
    ScrollViewer.VerticalScrollBarVisibility="Hidden">
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <VariableSizedWrapGrid ItemHeight="180" Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
</local:MyGridView>

随同

MyGridView.cs

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace App1
{
    public class MyGridView : GridView
    {
        private int _columnCount = 1;
        private double _itemWidth = 100;

        public double MinItemWidth
        {
            get { return (double) GetValue( MinItemWidthProperty ); }
            set { SetValue( MinItemWidthProperty, value ); }
        }

        // Using a DependencyProperty as the backing store for MinItemWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MinItemWidthProperty =
            DependencyProperty.Register( "MinItemWidth", typeof( double ), typeof( MyGridView ), new PropertyMetadata( 100.0 ) );


        public double MaxItemWidth
        {
            get { return (double) GetValue( MaxItemWidthProperty ); }
            set { SetValue( MaxItemWidthProperty, value ); }
        }

        // Using a DependencyProperty as the backing store for MaxItemWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaxItemWidthProperty =
            DependencyProperty.Register( "MaxItemWidth", typeof( double ), typeof( MyGridView ), new PropertyMetadata( 200.0 ) );


        private long _itemsPanelPropertyChangedToken;

        public MyGridView()
        {
            _itemsPanelPropertyChangedToken = RegisterPropertyChangedCallback( ItemsPanelProperty, ItemsPanelChangedAsync );
        }

        private async void ItemsPanelChangedAsync( DependencyObject sender, DependencyProperty dp )
        {
            UnregisterPropertyChangedCallback( ItemsPanelProperty, _itemsPanelPropertyChangedToken );
            await this.Dispatcher.RunIdleAsync( ItemsPanelChangedCallback );
        }

        private void ItemsPanelChangedCallback( IdleDispatchedHandlerArgs e )
        {
            var wg = ItemsPanelRoot as VariableSizedWrapGrid;
            if (wg != null)
            {
                wg.ItemWidth = _itemWidth;
            }
        }

        protected override void PrepareContainerForItemOverride( DependencyObject element, object item )
        {
            var itemIndex = this.Items.IndexOf( item );

            element.SetValue( VariableSizedWrapGrid.RowSpanProperty, GetRowSpanByColumnCountAndIndex( _columnCount, itemIndex ) );
            element.SetValue( VerticalContentAlignmentProperty, VerticalAlignment.Stretch );
            element.SetValue( HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch );
            base.PrepareContainerForItemOverride( element, item );
        }

        private static readonly Dictionary<int, int[]> _rowSpanLayout = new Dictionary<int, int[]>
        {
            [ 1 ] = new int[] { /* 5 */ 2, 2, 2, 2, 2, /* 6 */ 2, 2, 2, 2, 2, 2, /* 7 */ 2, 2, 2, 2, 2, 2, 2, /* 8 */ 2, 2, 2, 2, 2, 2, 2, 2, /* 9 */ 2, 2, 2, 2, 2, 2, 2, 2, 2 },
            [ 2 ] = new int[] { /* 5 */ 2, 1, 2, 2, 1, /* 6 */ 3, 3, 3, 2, 2, 2, /* 7 */ 3, 3, 1, 2, 3, 1, 1, /* 8 */ 2, 3, 2, 3, 3, 3, 3, 1, /* 9 */ 3, 2, 1, 3, 2, 2, 3, 1, 1 },
            [ 3 ] = new int[] { /* 5 */ 3, 2, 2, 1, 1, /* 6 */ 2, 3, 2, 3, 3, 2, /* 7 */ 3, 3, 3, 2, 1, 2, 1, /* 8 */ 2, 3, 3, 1, 2, 1, 2, 1, /* 9 */ 3, 3, 3, 1, 2, 1, 3, 3, 2 },
            [ 4 ] = new int[] { /* 5 */ 2, 2, 1, 2, 1, /* 6 */ 3, 3, 2, 2, 1, 1, /* 7 */ 3, 2, 2, 2, 1, 1, 1, /* 8 */ 3, 3, 3, 3, 2, 2, 2, 2, /* 9 */ 3, 3, 3, 2, 2, 2, 2, 2, 1 },
            [ 5 ] = new int[] { /* 5 */ 2, 2, 2, 2, 2, /* 6 */ 2, 2, 2, 1, 2, 1, /* 7 */ 3, 3, 3, 2, 2, 1, 1, /* 8 */ 3, 3, 2, 2, 2, 1, 1, 1, /* 9 */ 3, 2, 2, 2, 2, 1, 1, 1, 1 },
        };

        private int GetRowSpanByColumnCountAndIndex( int columnCount, int itemIndex )
        {
            return _rowSpanLayout[ columnCount ][ itemIndex % 35 ];
        }

        protected override Size MeasureOverride( Size availableSize )
        {
            System.Diagnostics.Debug.WriteLine( availableSize );

            int columnCount = _columnCount;
            double availableWidth = availableSize.Width;

            double itemWidth = availableWidth / columnCount;

            while ( columnCount > 1 && itemWidth < Math.Min( MinItemWidth, MaxItemWidth ) )
            {
                columnCount--;
                itemWidth = availableWidth / columnCount;
            }

            while ( columnCount < 5 && itemWidth > Math.Max( MinItemWidth, MaxItemWidth ) )
            {
                columnCount++;
                itemWidth = availableWidth / columnCount;
            }

            var wg = this.ItemsPanelRoot as VariableSizedWrapGrid;

            _itemWidth = itemWidth;
            if ( _columnCount != columnCount )
            {
                _columnCount = columnCount;
                if ( wg != null )
                {
                    Update( );
                }
            }

            if ( wg != null )
            {
                wg.ItemWidth = itemWidth;
            }

            return base.MeasureOverride( availableSize );
        }

        // refresh the variablesizedwrapgrid layout
        private void Update()
        {
            if ( !( this.ItemsPanelRoot is VariableSizedWrapGrid ) )
                throw new ArgumentException( "ItemsPanel is not VariableSizedWrapGrid" );

            int itemIndex = 0;
            foreach ( var container in this.ItemsPanelRoot.Children.Cast<GridViewItem>( ) )
            {
                int rowSpan = GetRowSpanByColumnCountAndIndex( _columnCount, itemIndex );
                VariableSizedWrapGrid.SetRowSpan( container, rowSpan );
                itemIndex++;
            }

            this.ItemsPanelRoot.InvalidateMeasure( );
        }
    }
}

MyGridViewTemplateSelector.cs

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace App1
{
    public class MyGridViewTemplateSelector : DataTemplateSelector
    {
        public DataTemplate Small { get; set; }
        public DataTemplate Medium { get; set; }
        public DataTemplate Large { get; set; }

        protected override DataTemplate SelectTemplateCore( object item, DependencyObject container )
        {
            var rowSpan = container.GetValue( VariableSizedWrapGrid.RowSpanProperty );

            int index;
            try
            {
                dynamic model = item;
                index = model.Index;
            }
            catch ( Exception )
            {
                index = -1;
            }
            long token = 0;

            DependencyPropertyChangedCallback lambda = ( sender, dp ) =>
            {
                container.UnregisterPropertyChangedCallback( VariableSizedWrapGrid.RowSpanProperty, token );

                var cp = (ContentControl) container;
                cp.ContentTemplateSelector = null;
                cp.ContentTemplateSelector = this;
            };

            token = container.RegisterPropertyChangedCallback( VariableSizedWrapGrid.RowSpanProperty, lambda );

            switch ( rowSpan )
            {
                case 1:
                    return Small;
                case 2:
                    return Medium;
                case 3:
                    return Large;
                default:
                    throw new InvalidOperationException( );
            }
        }

        private void Foo( DependencyObject sender, DependencyProperty dp )
        {
            throw new NotImplementedException( );
        }
    }
}

要在此处完成其他文件

MainPage.xaml

代码语言:javascript
复制
<Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.Resources>

        <DataTemplate x:Key="Small">
            <Grid Margin="5">
                <Grid.Background>
                    <SolidColorBrush Color="{Binding Path=Color}"/>
                </Grid.Background>
                <StackPanel VerticalAlignment="Top">
                    <StackPanel.Background>
                        <SolidColorBrush Color="White" Opacity="0.75"/>
                    </StackPanel.Background>

                    <TextBlock FontSize="15" Margin="10">
                        <Run Text="{Binding Path=Index}"/>. <Run Text="{Binding Path=Name}"/>
                    </TextBlock>
                    <TextBlock Text="Small" TextAlignment="Center"/>
                </StackPanel>
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="Medium">
            <Grid Margin="5">
                <Grid.Background>
                    <SolidColorBrush Color="{Binding Path=Color}"/>
                </Grid.Background>
                <StackPanel VerticalAlignment="Top">
                    <StackPanel.Background>
                        <SolidColorBrush Color="White" Opacity="0.75"/>
                    </StackPanel.Background>

                    <TextBlock FontSize="15" Margin="10">
                        <Run Text="{Binding Path=Index}"/>. <Run Text="{Binding Path=Name}"/>
                    </TextBlock>
                    <TextBlock Text="Medium" TextAlignment="Center"/>
                </StackPanel>
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="Large">
            <Grid Margin="5">
                <Grid.Background>
                    <SolidColorBrush Color="{Binding Path=Color}"/>
                </Grid.Background>
                <StackPanel VerticalAlignment="Top">
                    <StackPanel.Background>
                        <SolidColorBrush Color="White" Opacity="0.75"/>
                    </StackPanel.Background>

                    <TextBlock FontSize="15" Margin="10">
                        <Run Text="{Binding Path=Index}"/>. <Run Text="{Binding Path=Name}"/>
                    </TextBlock>
                    <TextBlock Text="Large" TextAlignment="Center"/>
                </StackPanel>
            </Grid>

        </DataTemplate>
        <local:MyGridViewTemplateSelector x:Key="MyGridTemplateSelector"
                                          Small="{StaticResource Small}"
                                          Medium="{StaticResource Medium}"
                                          Large="{StaticResource Large}"/>
    </Page.Resources>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="48"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="48"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <!-- top left section -->

        <Border Background="#D13438">

        </Border>

        <!-- top bar -->

        <Border Grid.Column="1" Grid.Row="0" Padding="5" Background="#F2F2F2">
            <TextBlock Text="MenuBar" VerticalAlignment="Center"/>
        </Border>

        <!-- left bar -->

        <Border Grid.Column="0" Grid.Row="1" Width="48" Background="#2B2B2B">

        </Border>

        <!-- content -->

        <Border Grid.Column="1" Grid.Row="1" Background="#E6E6E6">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="48"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <Border Grid.Row="0" Padding="5" Background="#F2F2F2">
                    <TextBlock Text="SectionBar" VerticalAlignment="Center"/>
                </Border>
                <ScrollViewer Grid.Row="1">
                    <Border Margin="7,7,10,7">

                        <!-- the wrapped news items -->

                        <local:MyGridView ItemsSource="{Binding}" ItemTemplateSelector="{StaticResource MyGridTemplateSelector}" MinItemWidth="300" MaxItemWidth="600" ScrollViewer.VerticalScrollBarVisibility="Hidden">
                            <GridView.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <VariableSizedWrapGrid ItemHeight="180" Orientation="Horizontal"/>
                                </ItemsPanelTemplate>
                            </GridView.ItemsPanel>
                        </local:MyGridView>

                    </Border>
                </ScrollViewer>
            </Grid>
        </Border>
    </Grid>
</Page>

MainPage.xaml.cs

代码语言:javascript
复制
using System.Linq;
using Windows.UI;
using Windows.UI.Xaml.Controls;
using System.Reflection;

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

            // just some sample data

            var colors = typeof( Colors )
                .GetRuntimeProperties( )
                .Take( 140 )
                .Select( ( x, index ) => new
                {
                    Color = (Color) x.GetValue( null ),
                    Name = x.Name,
                    Index = index,
                } );
            this.DataContext = colors;
        }

    }
}

如果你曾经想过“我从某个地方知道”,你应该看看Jerry Nixon's blog :o)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32436208

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档