带有 ListboxItems 的列表/字段,其中显示多边形

List/Field with ListboxItems in which the polygons are displayed

提问人:FelixFeuerdorn 提问时间:4/30/2023 更新时间:5/3/2023 访问量:47

问:

一段时间以来,我一直在尝试创建一个三角形列表,为此,我继承了一个 ListBoxItem 并给了它们一个多边形。但不幸的是,三角形没有以任何方式向我显示,我不明白为什么它不起作用。

这是我目前拥有的代码: 三角形的 PolygonItem 之后,ViewModel 中的 PolygonItems 列表和要显示该内容的 XAML 代码,首先直接在 MainWindow 中显示。

public ObservableCollection<PolygonItem> PolygonItems { get; set; }

public MainViewModel() {
    PolygonItems = new ObservableCollection<PolygonItem>() {
        new PolygonItem
        {
            Polygon = new Polygon
            {
                Width = 100,
                Height = 100,
                Points = new PointCollection
                {
                    new Point(40, 40),
                    new Point(100, 40),
                    new Point(70, 100),
                }
            }
        },
    };
}


public class PolygonItem: ListBoxItem
{
    public Polygon Polygon { get; set; }
}

public class PointCollectionConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if(value is PointCollection points)
        {
            return string.Join(" ", points.Select(p => $"{p.X},{p.Y}"));
        }
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is string pointsString)
        {
            var pointsArray = pointsString.Split(' ');
            var pointCollection = new PointCollection();
            foreach(var point in pointsArray)
            {
                var pointsValues = point.Split(',');
                if(pointsValues.Length == 2
                    && double.TryParse(pointsValues[0], out var x)
                    && double.TryParse(pointsValues[1], out var y))
                {
                    pointCollection.Add(new System.Windows.Point(x, y));
                }
            }
            return pointCollection;
        }
        return null;
    }
}

<Grid>
    <ListBox ItemsSource="{Binding PolygonItems}" Width="300" Height="300">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Polygon Points="{Binding Path=Polygon.Points,
                    Converter={StaticResource PointCollectionConverter}}"
                         Stroke="Black" Fill="Aquamarine">
                </Polygon>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>
C# WPF 模板 用户控件

评论

0赞 emoacht 5/1/2023
你的 PolygonItem 毫无意义。此外,当绑定到另一个 Polygon.Points 时,将 Polygon.Points 转换为字符串是没有意义的。
0赞 Clemens 5/2/2023
视图模型中不应有多边形。Polygon 是一个 UI 元素,因此是一个视图元素。ListBox 的 ItemTemplate 将声明一个 Poylgon,该 Poylgon 的 Points 属性绑定到视图模型属性。
0赞 FelixFeuerdorn 5/3/2023
如果我想要一个三角形的列表/字段 (2D),我还能怎么做,我一筹莫展,并且会对一个简洁的解决方案感到满意。我只想创建 3 个点,给三角形并显示它,因为我不知道任何其他方法可以用多边形做到这一点,如果有人能在那里给我一个解决方案,那就太好了。
0赞 Clemens 5/3/2023
如果没有 ItemContainerStyle,您将生成与类似的内容。如前所述,在 ItemTemplate 中声明一个 Polygon,并将其 Points 属性绑定到视图模型项的属性。在开始之前,请阅读数据模板概述

答:

1赞 Markus 5/3/2023 #1

XAML的

<Window x:Class="WpfPolygonApp.MainWindow"
        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"
        xmlns:local="clr-namespace:WpfPolygonApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" d:DataContext="{d:DesignInstance  local:MainWindowViewModel}">
    <Grid>
        <ItemsControl ItemsSource="{Binding Items}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Polygon Stroke="Brown" StrokeThickness="2" Points="{Binding Points}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

C#

using System.Windows.Media;

namespace WpfPolygonApp {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
            DataContext = new MainWindowViewModel();
        }
    }

    public class MainWindowViewModel : ViewModelBase {
        private readonly ObservableCollection<ItemViewModel> _items;

        public MainWindowViewModel() {
            _items = new ObservableCollection<ItemViewModel>();
            _items.Add(new ItemViewModel(new List<Point> { new Point(10, 20), new Point(20, 20), new Point(30, 40) }));
            _items.Add(new ItemViewModel(new List<Point> { new Point(20, 20), new Point(10, 20), new Point(50, 50) }));
        }
        public ObservableCollection<ItemViewModel> Items => _items;
    }

    public class ItemViewModel: ViewModelBase {
        private readonly PointCollection _points;

        public ItemViewModel(List<Point> points) {
            _points = new PointCollection();
            foreach (var point in points) {
                _points.Add(point);
            }
        }

        public PointCollection Points => _points;
    }

    public class ViewModelBase : INotifyPropertyChanged {
        public event PropertyChangedEventHandler? PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

这也适用于 Listbox...