开发者

WPF - How to center column data in ListView?

I'm still learning WPF, but I'm really confused about something that should be really simple. What I want to do is to center the contents of the 3rd and 4th columns. When I run this, the columns are left justified:

<ListView Margin="0" x:Name="listMonitoredUrls" AlternationCount="1"
          ItemsSource="{Binding}"  >
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Description" DisplayMemberBinding="{Binding FriendlyDesc}"/>
            <GridViewColumn Header="Url" DisplayMemberBinding="{Binding Url}"/>
            <GridViewColumn Header="Frequency">
                <GridViewColumn.CellTemplate >
                    <DataTemplate>
                        <TextBlock Text="{Binding ScanFrequencyMinutes}"
                                   HorizontalAlignment="Center"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Header="Next Scan"  >
                <GridViewColumn.CellTemplate >
                    <DataTemplate>
                        <TextB开发者_如何学JAVAlock Text="{Binding TimeNextScanStr}"
                                   HorizontalAlignment="Center"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

I"m really starting to like WPF, but some simple things like this seem to be really hard.


Try using the TextAlignment property instead of HorizontalAlignment - should do it. To my understanding HorizontalAlignment="Center" will center your textblock not the text in it.


This might be a long shot but i've had to do it for listboxes where the items are defined by templates. Try setting the HorizontalContentAlignment="Stretch" on your ListView. If I don't set that the items take only as much space as they need and are left justified.


I've created a solution which works under the common scenario of:

<GridViewColumn Header="Some Property" DisplayMemberBinding="{Binding SomeProperty}" />

where one only wants a simple DisplayMemberBinding with text without having to specify a CellTemplate

the new code uses an attached property and becomes:

<GridViewColumn Header="Some Property" DisplayMemberBinding="{Binding SomeProperty}" 
                ctrl:GridViewExtensions.IsContentCentered="True" />

attached property code:

public static class GridViewExtensions
{
    #region IsContentCentered

    [Category("Common")]
    [AttachedPropertyBrowsableForType(typeof(GridViewColumn))]
    public static bool GetIsContentCentered(GridViewColumn gridViewColumn)
    {
        return (bool)gridViewColumn.GetValue(IsContentCenteredProperty);
    }
    public static void SetIsContentCentered(GridViewColumn gridViewColumn, bool value)
    {
        gridViewColumn.SetValue(IsContentCenteredProperty, value);
    }

    public static readonly DependencyProperty IsContentCenteredProperty = 
        DependencyProperty.RegisterAttached(
            "IsContentCentered",
            typeof(bool), // type
            typeof(GridViewExtensions), // containing type
            new PropertyMetadata(default(bool), OnIsContentCenteredChanged)
            );

    private static void OnIsContentCenteredChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        OnIsContentCenteredChanged((GridViewColumn)d, (bool)e.NewValue);
    }
    private static void OnIsContentCenteredChanged(GridViewColumn gridViewColumn, bool isContentCentered)
    {
        if (isContentCentered == false) { return; }
        // must wait a bit otherwise GridViewColumn.DisplayMemberBinding will not yet be initialized, 
        new DispatcherTimer(TimeSpan.FromMilliseconds(100), DispatcherPriority.Normal, OnColumnLoaded, gridViewColumn.Dispatcher)
        {
            Tag = gridViewColumn
        }.Start();
    }

    static void OnColumnLoaded(object sender, EventArgs e)
    {
        var timer = (DispatcherTimer)sender;
        timer.Stop();

        var gridViewColumn = (GridViewColumn)timer.Tag;
        if (gridViewColumn.DisplayMemberBinding == null)
        {
            throw new Exception("Only allowed with DisplayMemberBinding.");
        }
        var textBlockFactory = new FrameworkElementFactory(typeof(TextBlock));
        textBlockFactory.SetBinding(TextBlock.TextProperty, gridViewColumn.DisplayMemberBinding);
        textBlockFactory.SetValue(TextBlock.TextAlignmentProperty, TextAlignment.Center);
        var cellTemplate = new DataTemplate { VisualTree = textBlockFactory };
        gridViewColumn.DisplayMemberBinding = null; // must null, otherwise CellTemplate won't be recognized
        gridViewColumn.CellTemplate = cellTemplate;
    }

    #endregion IsContentCentered

}


Here is my example to show a working xaml:

<Window x:Class="WPF_Tutorial.Rich_text_controls.BlockUIContainerCenteredColumnSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        xmlns:self="clr-namespace:WPF_Tutorial.Rich_text_controls"
        Title="BlockUIContainerCenteredColumnSample" Height="275" Width="300"
        WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <x:Array x:Key="UserArray" Type="{x:Type self:User}">
            <self:User Name="John Doe" Age="42" />
            <self:User Name="Jane May-Anne Josephine Renalds Doe" Age="36" />
        </x:Array>
    </Window.Resources>
    <Grid>
        <FlowDocumentScrollViewer>
            <FlowDocument>
                <Paragraph FontSize="36" Margin="0">Users</Paragraph>
                <Paragraph FontStyle="Italic" TextAlignment="Left" FontSize="14" Foreground="Gray">Here's a list of our users, inside our FlowDocument, in a completely interactive ListView control!</Paragraph>
                <BlockUIContainer>
                    <ListView BorderThickness="0" ItemsSource="{StaticResource UserArray}" HorizontalAlignment="Center">
                        <ListView.ItemContainerStyle>
                            <Style TargetType="ListViewItem">
                                <!-- This stretches out the TextBlock width to the column width -->
                                <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                            </Style>
                        </ListView.ItemContainerStyle>
                        <ListView.View>
                            <GridView>
                                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="150" />
                                <GridViewColumn>
                                    <GridViewColumnHeader Content="Age" Width="75" />
                                    <GridViewColumn.CellTemplate>
                                        <DataTemplate>
                                            <TextBlock Text="{Binding Age}" TextAlignment="Center" />
                                        </DataTemplate>
                                    </GridViewColumn.CellTemplate>
                                </GridViewColumn>
                            </GridView>
                        </ListView.View>
                    </ListView>
                </BlockUIContainer>
                <Paragraph FontStyle="Italic" TextAlignment="Left" FontSize="14" Foreground="Gray">More content can go here...</Paragraph>
            </FlowDocument>
        </FlowDocumentScrollViewer>
    </Grid>
</Window>

Notice the <ListView.ItemContainerStyle> block. It has the <Setter .... Without this, as per AndyG's text, nothing will work the way you want.

This has been very frustrating trying to work out.

By the way, here is the backing-code for this xaml:

namespace WPF_Tutorial.Rich_text_controls
{
    using System.Windows;

    public partial class BlockUIContainerCenteredColumnSample : Window
    {
        public BlockUIContainerCenteredColumnSample()
        {
            InitializeComponent();
        }
    }

    public class User
    {
        public int Age { get; set; }

        public string Name { get; set; }
    }
}

What you should see when run

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜