XAML Winui 3 ListView -在列表项之间显示按钮

djp7away  于 2022-12-07  发布在  其他
关注(0)|答案(1)|浏览(143)

我正在尝试通过开发一个可以帮助计划假期的应用程序来学习WinUI。我正在尝试做的事情之一是创建一个显示目的地列表的UI(目前使用的是ListView),然后在右边有一个按钮,实际上指向它们之间的线,可以弹出两个目的地之间的“旅行”UI。
这是我想要达到的目标的模型:

带有画得不好的飞机和火车图标的按钮应该代表两个位置之间的旅行,因此应该在中间。
我主要是在尝试使用DataTemplate内部的网格来让它工作,但一直无法在不使目标之间差距更大的情况下获得“中途”对齐。
有人对我如何实现这一目标有什么建议吗,或者这是一个愚蠢的差事?

kokeuurv

kokeuurv1#

我猜你需要创建一个用户控件(或者自定义控件)。

自定义列表.xaml

<UserControl
    x:Class="UserControls.CustomList"
    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:local="using:UserControls"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid x:Name="RootContainer" />

</UserControl>

自定义列表.xaml

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using System.Collections.Generic;
using Windows.Foundation.Collections;

namespace UserControls;

public sealed partial class CustomList : UserControl
{
    public static readonly DependencyProperty MainItemsProperty = DependencyProperty.Register(
        nameof(MainItems),
        typeof(IEnumerable<string>),
        typeof(CustomList),
        new PropertyMetadata(default, (d, e) => (d as CustomList)?.OnItemsPropertyChanged()));

    public static readonly DependencyProperty SubItemsProperty = DependencyProperty.Register(
        nameof(SubItems),
        typeof(IEnumerable<string>),
        typeof(CustomList),
        new PropertyMetadata(default, (d, e) => (d as CustomList)?.OnItemsPropertyChanged()));

    public CustomList()
    {
        this.InitializeComponent();
        this.RootContainer.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(0, GridUnitType.Auto) });
        this.RootContainer.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(0, GridUnitType.Auto) });
    }

    public IEnumerable<string> MainItems
    {
        get => (IEnumerable<string>)GetValue(MainItemsProperty);
        set => SetValue(MainItemsProperty, value);
    }

    public IEnumerable<string> SubItems
    {
        get => (IEnumerable<string>)GetValue(SubItemsProperty);
        set => SetValue(SubItemsProperty, value);
    }

    private ICollectionView? MainItemsCollectionView { get; set; }

    private ICollectionView? SubItemsCollectionView { get; set; }

    private void OnItemsPropertyChanged()
    {
        CollectionViewSource mainCollectionViewSource = new()
        {
            Source = MainItems
        };

        if (MainItemsCollectionView is not null)
        {
            MainItemsCollectionView.VectorChanged -= ItemsCollectionView_VectorChanged;
        }

        MainItemsCollectionView = mainCollectionViewSource.View;
        MainItemsCollectionView.VectorChanged += ItemsCollectionView_VectorChanged;

        CollectionViewSource subCollectionViewSource = new()
        {
            Source = SubItems
        };

        SubItemsCollectionView = subCollectionViewSource.View;

        RefreshList();
    }

    private void ItemsCollectionView_VectorChanged(IObservableVector<object> sender, IVectorChangedEventArgs @event)
    {
        RefreshList();
    }

    private void RefreshList()
    {
        this.RootContainer.Children.Clear();
        this.RootContainer.RowDefinitions.Clear();

        if (MainItemsCollectionView is not null)
        {
            UpdateRowDefinitions(MainItemsCollectionView.Count);

            for (int i = 0; i < MainItemsCollectionView.Count; i++)
            {
                TextBlock mainItemTextBlock = new()
                {
                    Text = MainItemsCollectionView[i] as string,
                };

                Grid.SetColumn(mainItemTextBlock, 0);
                Grid.SetRow(mainItemTextBlock, i * 2);
                Grid.SetRowSpan(mainItemTextBlock, 2);
                this.RootContainer.Children.Add(mainItemTextBlock);

                if (SubItemsCollectionView?.Count > i)
                {
                    TextBlock subItemTextBlock = new()
                    {
                        Text = SubItemsCollectionView[i] as string,
                    };

                    Grid.SetColumn(subItemTextBlock, 1);
                    Grid.SetRow(subItemTextBlock, (i * 2) + 1);
                    Grid.SetRowSpan(subItemTextBlock, 2);
                    this.RootContainer.Children.Add(subItemTextBlock);
                }
            }
        }
    }

    private void UpdateRowDefinitions(int mainItemsCount)
    {
        int requiredRowsCount = mainItemsCount * 2;

        while (this.RootContainer.RowDefinitions.Count != requiredRowsCount)
        {
            if (this.RootContainer.RowDefinitions.Count < requiredRowsCount)
            {
                this.RootContainer.RowDefinitions.Add(new RowDefinition()
                {
                    Height = new GridLength(0, GridUnitType.Auto),
                });

                continue;
            }

            if (this.RootContainer.RowDefinitions.Count > requiredRowsCount)
            {
                this.RootContainer.RowDefinitions.RemoveAt(this.RootContainer.RowDefinitions.Count - 1);
                continue;
            }
        }
    }
}

主页面视图模型.cs

using CommunityToolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;

namespace UserControls;

public partial class MainPageViewModel : ObservableObject
{
    [ObservableProperty]
    private ObservableCollection<string> mainItems = new()
    {
        "New York",
        "London",
        "Edinburgh"
    };

    [ObservableProperty]
    private ObservableCollection<string> subItems = new()
    {
        "Airplane",
        "Train",
    };
}

主页面.xaml

<Grid>
    <local:CustomList
        MainItems="{x:Bind ViewModel.MainItems, Mode=OneWay}"
        SubItems="{x:Bind ViewModel.SubItems, Mode=OneWay}" />
</Grid>

相关问题