【问题标题】:Autosize column in ListView (UWP)ListView (UWP) 中的自动调整列大小
【发布时间】:2018-05-06 18:48:05
【问题描述】:

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

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

那么,我怎样才能制作一个 Auto 列...或模拟它?

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

编辑:使用@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>

代码:

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

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

预期结果是:

但是,实际结果是:

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

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

【问题讨论】:

  • 你考虑过使用RelativePanel吗?
  • 你会如何使用它?请在 OP 中获取代码 :) 谢谢!

标签: c# .net xaml layout uwp


【解决方案1】:

问题是 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# 视图模型

    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;
    }

【讨论】:

  • 哎呀,这太棘手了,使得 ViewModel 与 View 过于耦合:(
  • @SuperJMN 嗯。但是,如果不这样做,您的 ListView 很难理解它应该如何呈现自己。使用“自动”它会根据您的内容进行自我调整,这不是您需要的。
  • 是的,就是这样。我想知道一些像“DataGrids”这样的控件是如何实现这种效果的。如您所知,这些控件具有列的含义,其中一个项目的宽度会影响其余项目的宽度。
【解决方案2】:

尝试为 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 属性设置适当的值。

【讨论】:

  • 嘿@WPFInfo!请检查更新的OP。我试过你的答案,但它不起作用。我已经用边框替换了图像,以便代码更容易测试和查看问题。谢谢!
猜你喜欢
  • 2011-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多