简体   繁体   English

ListView(UWP)中的“自动调整大小”列

[英]Autosize column in ListView (UWP)

I would like to arrange my items in a ListView with a Text and an image like in this example: 我想将我的项目排列在具有文本和图像的ListView中,如以下示例所示:

在此处输入图片说明

  • The first column is automatic, so it expands to the widest element. 第一列是自动的,因此它会扩展到最宽的元素。
  • The second column should expand to fill the remaining space. 第二列应展开以填充剩余空间。

So, how can I make an Auto column... or simulate it? 那么,如何制作自动列...或对其进行仿真?

Obviously, the difficult part of this layout is that different elements have their widths depending on other element's widths. 显然,此布局的困难之处在于不同元素的宽度取决于其他元素的宽度。

EDIT: Using @WPInfo's answer, I've tried with this: 编辑:使用@WPInfo的答案,我已经尝试过:

XAML 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",
        };
    }
}

The expected result was: 预期结果是:

在此处输入图片说明

However, the actual result is: 但是,实际结果是:

在此处输入图片说明

The goal is that the first column to be as wide as the widest element inside it. 目的是使第一列与它内部的最宽元素一样宽。

In WPF, this is solved easily with the use of Grid.SharedSizeGroup . 在WPF中,可以使用Grid.SharedSizeGroup轻松解决此问题。 In UWP there is not such a thing. 在UWP中没有这样的事情。

The problem is that ListView children don't know anything about each other. 问题在于ListView子级彼此之间一无所知。 There's no simple trick to have all the items know what the longest text item is, so a more complicated solution is required. 让所有项目都知道最长的文本项目不是简单的技巧,因此需要更复杂的解决方案。 The following works. 以下作品。 It will determine a fixed TextBlock size based on the largest item from the string list, and it will update it should the font size change. 它将基于字符串列表中的最大项确定固定的TextBlock大小,并且如果字体大小更改,它将更新该大小。 Obviously a simpler solution closer resembling your example code can be had if you decide on a fixed column size for either the text or the image, but I assume you already know that. 显然,如果您为文本或图像确定固定的列大小,则可以采用更类似于示例代码的简单解决方案,但是我想您已经知道了。

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

Try setting ItemContainerStyle property for the ListView: 尝试为ListView设置ItemContainerStyle属性:

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

Then your ListView may look like this: 然后您的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>

After that, you can set a proper value for HorizontalAlignment property of your ListView. 之后,可以为ListView的HorizontalAlignment属性设置适当的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM