在ListView(UWP)中自动调整列

时间:2017-11-22 22:18:25

标签: c# .net xaml layout uwp

我想在ListView中安排我的项目,其中包含文本和图像,如下例所示:

enter image description here

  • 第一列是自动的,因此它会扩展为最宽的元素。
  • 第二列应展开以填充剩余空间。

那么,我如何制作一个自动列......或模拟它?

显然,这种布局的难点在于不同的元素的宽度取决于其他元素的宽度。

编辑:使用@ WPInfo的答案,我已尝试过这个:

XAML

<Page.DataContext>
    <local:MainViewModel></local:MainViewModel>
</Page.DataContext>
<ListView ItemsSource="{Binding Items}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding}"  />
                <Border Background="CornflowerBlue" Grid.Column="1" />
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>

</ListView>

CODE:

public class MainViewModel
{
    public IList<string> Items { get; }

    public MainViewModel()
    {
        Items = new List<string>()
        {
            "ABC",
            "ABCDEF",
            "ABCDEFGHI",
        };
    }
}

预期结果是:

enter image description here

然而,实际结果是:

enter image description here

目标是第一列与其中最宽的元素一样宽。

在WPF中,使用Grid.SharedSizeGroup可以轻松解决这个问题。在UWP中没有这样的事情。

2 个答案:

答案 0 :(得分:0)

问题是ListView孩子对彼此一无所知。没有简单的技巧让所有项目都知道最长的文本项目是什么,因此需要更复杂的解决方案。以下作品。它将根据字符串列表中的最大项确定固定的TextBlock大小,如果字体大小发生更改,它将更新它。显然,如果您决定文本或图像的固定列大小,可以使用更接近您的示例代码的更简单的解决方案,但我认为您已经知道了。

XAML:

<Page.DataContext>
    <local:MainViewModel></local:MainViewModel>
</Page.DataContext>
<ListView ItemsSource="{Binding Items}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding MyText, Mode=OneWay}" FontSize="{Binding ItemFontSize, Mode=OneWay}" Width="{Binding TextWidth, Mode=OneWay}"  />
                <Border Background="CornflowerBlue" Grid.Column="1" />
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

C#ViewModel

    public class MainViewModel : INotifyPropertyChanged
    {
        public ObservableCollection<MyListViewItemsClass> Items { get; set; }

        private List<string> ItemsFromModel;

        private int _myFontSize;
        public int MyFontSize
        {
            get { return _myFontSize; }
            set
            {
                if (value != _myFontSize)
                {
                    _myFontSize = value;
                    OnPropertyChanged("MyFontSize");
                    // Font size changed, need to refresh ListView items
                    LoadRefreshMyListViewItems();
                }
            }
        }

        public MainViewModel()
        {
            // set default font size
            _myFontSize = 20;

            // example data
            ItemsFromModel = new List<string>()
        {
            "ABC",
            "ABCDEF",
            "ABCDEFGHI",
        };

            LoadRefreshMyListViewItems();
        }

        public void LoadRefreshMyListViewItems()
        {
            int itemMaxTextLength = 0;
            foreach (var modelItem in ItemsFromModel)
            {
                if (modelItem.Length > itemMaxTextLength) { itemMaxTextLength = modelItem.Length; }
            }
            Items = new ObservableCollection<MyListViewItemsClass>();
            // Convert points to pixels, multiply by max character length to determine fixed textblock width
            // This assumes 96 DPI. Search for how to grab system DPI in C# there are answers on SO. 
            double width = MyFontSize * 0.75 * itemMaxTextLength;
            foreach (var itemFromModel in ItemsFromModel)
            {
                var item = new MyListViewItemsClass();
                item.MyText = itemFromModel;
                item.ItemFontSize = MyFontSize;
                item.TextWidth = width;
                Items.Add(item);
            }
            OnPropertyChanged("Items");
        }

        public class MyListViewItemsClass
        {
            public string MyText { get; set; }
            public int ItemFontSize { get; set; }
            public double TextWidth { get; set; }
        }

        protected void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, e);
        }

        public void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

答案 1 :(得分:-1)

尝试为ListView设置ItemContainerStyle属性:

        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            </Style>
        </ListView.ItemContainerStyle>

然后你的ListView可能如下所示:

    <ListView x:Name="list">
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            </Style>
        </ListView.ItemContainerStyle>
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <TextBlock ... />
                    <Image Grid.Column="1" HorizontalAlignment="Right" ... />
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

之后,您可以为ListView的HorizontalAlignment属性设置正确的值。