0

I have been trying to create a list of triangles for a while now, to do this I inherited a ListBoxItem and gave them a polygon. But unfortunately the triangle is not shown to me in any way and I don't understand why it doesn't work.

This is the code I currently have: Once the PolygonItem for the triangle, a list of the PolygonItems in a ViewModel and the XAML code to display that, first directly in the 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>
  • Your PolygonItem is pointless. In addition, it does not make sense to convert a Polygon.Points to a string when bound to another Polygon.Points. – emoacht May 01 '23 at 15:13
  • There should not be a Polygon in a view model. Polygon is a UI element and hence a view element. The ItemTemplate of the ListBox would declare a Poylgon that has its Points property bound to a view model property. – Clemens May 02 '23 at 06:36
  • How else am I going to do this if I want a list/field (2D) of triangles, I'm at my wit's end and would be happy with a neat solution. I just want to create 3 points give the triangle that and display that, since I don't know any other way to do that with the polygon, it would be nice if someone could give me a solution there. – FelixFeuerdorn May 02 '23 at 16:41
  • You would build something similar to [this](https://stackoverflow.com/a/22325266/1136211) without the ItemContainerStyle. As already said, declare a Polygon in the ItemTemplate and bind its Points property to a property of the view model item. Read [Data Templating Overview](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/data/data-templating-overview?view=netframeworkdesktop-4.8) before you start. – Clemens May 02 '23 at 17:48

1 Answers1

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

This works also with Listbox...

Markus
  • 2,184
  • 2
  • 22
  • 32