如何将DataTemplate实现为子类网格?

时间:2016-02-25 01:27:56

标签: c# wpf templates grid subclass

我需要在网格中显示List<string>。 我需要能够在其中显示每个字符串,对于这个问题,让我们说TextBlock

我尝试使用ItemsControl,但它没有按我需要的方式工作,所以我考虑将网格控件子类化为ItemGrid把它作为DataContextIEnumerable(并忽略其他任何内容),并采用ItemTemplate来告诉控件如何显示内容。

我知道如何使用DataContext来显示内容,但我不知道如何在控件中实现模板。

到目前为止,我对控制的想法是:

public class ItemGrid : Grid {
    public static readonly DependencyProperty
        ColumnCountProperty = DependencyProperty.Register(
            "ColumnCount",
            typeof(int),
            typeof(ItemGrid),
            new PropertyMetadata( 1, OnColumnCountChanged ) ),
        ItemSourceProperty = DependencyProperty.Register(
            "ItemSource",
            typeof( IEnumerable<object> ),
            typeof( ItemGrid ),
            new PropertyMetadata( null, OnItemSourceChanged ) );

    private static void OnColumnsChanged(
        DependencyObject sender, DependencyPropertyChangedEventArgs e ) {
        ItemGrid IG = sender as ItemGrid;
        IG.ColumnDefinitions.Clear( );

        for ( int c = 0; c < ( int )e.NewValue; c++ )
            IG.ColumnDefinitions.Add( new ColumnDefinition( ) {
                Width = new GridLength( 1, GridUnitType.Star ) } );

        OnItemSourceChanged(
            sender,
            new DependencyPropertyChangedEventArgs(
                ItemSourceProperty, IG.ItemSource, IG.ItemSource ) );
    }

    private static void OnItemSourceChanged(
        DependencyObject sender, DependencyPropertyChangedEventArgs e ) {

        ItemGrid IG = sender as ItemGrid;
        int x = 0, rows;

        //This is the stub.
        //this is where the objects would be passed on to the DataTemplate.
        IEnumerable<UIElement> Children =
        ( e.NewValue as IEnumerable<object> ).Select( Child => new UIElement( ) );
        foreach( UIElement Child in Children ) {
            IG.Children.Add( Child );
            x = IG.Children.IndexOf( Child );
            SetColumn( Child, x % IG.ColumnCount );
            SetRow( Child, x / IG.ColumnCount );
        }

        rows = IG.Children.Cast<UIElement>( ).Max( Child => GetRow( Child ) ) + 1;

        for ( x = 0; x < rows; x++ )
            IG.RowDefinitions.Add(
                new RowDefinition( ) {
                    Height = new GridLength( 1, GridUnitType.Star ) } );
    }

    /// <summary>
    /// Get or Set Items Source.
    /// </summary>
    public IEnumerable<object> ItemSource {
        get { return this.GetValue( ItemSourceProperty ) as IEnumerable<object>; }
        set { this.SetValue( ItemSourceProperty, value ); }
    }

    /// <summary>
    /// Get or Set Number of Columns.
    /// </summary>
    public int ColumnCount {
        get { return ( int )this.GetValue( ColumnCountProperty ); }
        set { this.SetValue( ColumnCountProperty, value ); }
    }
}

OnItemSourceChanged方法中有一个存根,用于将对象选择为IEnumerable<UIElement>,然后将其分发到网格中。

这是我需要学习如何实现DataTemplate的地方,以及我需要帮助的地方。

我想尽可能地保留在XAML中,这样我基本上可以这样做:

<Controls:ItemGrid ColumnCount = "2" ItemSource = "{Binding Foo}">
    <Controls:ItemGrid.Template>
        <DataTemplate>
            <TextBlock Text = "{Binding Bar}"/>
        </DataTemplate>
    </Controls:ItemGrid.Template>
</Controls:ItemGrid>

在这样做的过程中,网格将填充后面的代码。 再一次 - 我尝试过使用ItemsControl,但它不起作用(即使得到articles I've read的所有帮助,我也无法获得它以我需要的方式工作。)

如何在此控件中实现模板?

编辑:

为清楚起见,这是我正在寻找的东西:

enter image description here

我能够找到答案here

1 个答案:

答案 0 :(得分:0)

您需要使用ItemsControl,但将ItemsPanel设置为2列UniformGrid,并将ItemTemplate设置为具有适当绑定的TextBlock。当控件不够高时,您还想将整个事物包装在ScrollViewer中,但您还要将ItemsControl的垂直对齐设置为top,以便当父ScrollViewer太高时,元素不会伸展出来:

<ScrollViewer ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto">
    <ItemsControl Name="myGrid" VerticalAlignment="Top">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Columns="2" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" FontSize="50" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" TextAlignment="Center" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ScrollViewer>

如果您只想要显示2行,则丢失ScrollViewer,将ItemControl的垂直对齐设置为拉伸并在UniformGrid中指定Rows="2"

<ItemsControl Name="myGrid">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Columns="2" Rows="2" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" FontSize="50" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" TextAlignment="Center" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>