未在 WPF DataTemplate 中绘制线

Line not being Drawn in WPF DataTemplate

我正在尝试收集正确的 WPF 数据模板以获得一个列表视图,每个项目都有一个 Border+Canvas(参见 ),然后在最后的每个项目 Canvas 上画一条线节点集合。它几乎可以工作,但目前我没有在 canvas 上绘制线条:在调试输出 Window 中,我看到:

System.Windows.Data Error: 40 : BindingExpression path error: 'CalloutGroup' property not found on 'object' ''CalloutGroup' (HashCode=35061213)'. BindingExpression:Path=CalloutGroup; DataItem='CalloutGroup' (HashCode=35061213); target element is 'ItemsControl' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')

这里是MainWindow.Xaml

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CalloutControl" x:Class="CalloutControl.MainWindow"
        Title="MainWindow" Height="430.597" Width="525">
    <Window.Resources>
        <DataTemplate x:Key="LineTemplate">
            <Line X1 ="{Binding X}" X2="{Binding X}" Stroke="Wheat" 
                      StrokeThickness="10" Y1="{Binding Y}" Y2="{Binding Y}"/>
        </DataTemplate>


        <DataTemplate x:Key="GroupTemplate">
        <Border Width="200" Height ="{Binding DistributionHeight}" BorderThickness="5" Background="Brown" BorderBrush="Red">
                <ItemsControl ItemsSource="{Binding Path=CalloutGroup}" 
                          ItemTemplate="{StaticResource LineTemplate}">
                    <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas Background="Beige"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </Border>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Border>
        <ListView ItemsSource="{Binding Groups}"
                      ItemTemplate="{StaticResource GroupTemplate}">

        </ListView>
        </Border>
    </Grid>
</Window>

MainWindow.xaml.cs

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace CalloutControl
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var vm = new MainWindowViewModel();
            DataContext = vm;
        }
    }
}

然后是 ViewModel -> MainWindowViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;

namespace CalloutControl
{
    public class CalloutItem            : INotifyPropertyChanged
    {
        public CalloutItem()
        {

        }
        public CalloutItem (int length,
                   int itemNum,
                     double x,
                    double y ){
                        Length = length;
                        ItemNum = itemNum;
                        X = x;
                        Y =  y;
        }
        private int length;

        public int Length
        {
            get { return length; }
            set
            {
                length = value;
                OnPropertyChanged("Length");
            }
        }
        private int itemNum;

        public int ItemNum
        {
            get { return itemNum; }
            set { itemNum = value;
            OnPropertyChanged("ItemNum");
            }
        }
        //public int      ItemNum;
        private double x;

        public double X
        {
            get { return x; }
            set { x = value;
                  OnPropertyChanged("X");
            }
        }
        private double y;

        public double Y
        {
            get { return y; }
            set { y = value;
            OnPropertyChanged("Y");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
    public class CalloutGroup           : INotifyPropertyChanged
    {
        ObservableCollection<CalloutItem> group = new ObservableCollection<CalloutItem>();
        public CalloutGroup(int nItems)
        {
            NumItems = nItems;

        }
        public ObservableCollection<CalloutItem> Group
        {
            get { return group; }
            set
            {
                group = value;
                OnPropertyChanged("Group");
            }
        }
        private double distributionHeight = 400;

        public double DistributionHeight
        {
            get { return distributionHeight; }
            set
            {
                distributionHeight = value;
                Redistribute();
                OnPropertyChanged("DistributionHeight");
            }
        }


        private void Redistribute()
        {
            double step = distributionHeight / numItems;
            double currY = step / 2 ;
            var redistArr = group.ToArray();

            for (int i = 0; i < group.Count(); i++)
            {
                redistArr[i].Y = currY;
                currY += step;
            }
            OnPropertyChanged("Group");
        }
        private int numItems = 10;

        public int NumItems
        {
            get { return numItems; }
            set
            {
                numItems = value;
                group.Clear();
                for (int i = 0; i < numItems; i++)
                {
                    group.Add(new CalloutItem());
                }
                Redistribute();
                OnPropertyChanged("NumItems");
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }

    public class MainWindowViewModel    : INotifyPropertyChanged
    {

        ObservableCollection<CalloutGroup> groups = new ObservableCollection<CalloutGroup>();

        public ObservableCollection<CalloutGroup> Groups
        {
            get { return groups; }
            set { groups = value;
                  OnPropertyChanged("Groups");
            }
        }
        public MainWindowViewModel ()
        {
            groups.Add(new CalloutGroup(3));
            groups.Add(new CalloutGroup(3));

        }


        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

您似乎缺少 X1 绑定中的 {}

您的代码有问题:

行有相同的StartPointEndPoint,所以即使没有其他错误,这个点也不会出现。

在您的项目模板中,而不是

<ItemsControl ItemsSource="{Binding Group}"

您使用:

<ItemsControl ItemsSource="{Binding Path=CalloutGroup}"`

这里是稍微修改过的代码,我在你的代码中添加了 X2、Y2。您可以根据需要进行更改。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace CalloutControl
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var vm = new MainWindowViewModel();

            vm.Groups.Add(new CalloutControl.CalloutGroup(2));
            vm.Groups.Add(new CalloutControl.CalloutGroup(2));

            vm.Groups[0].Group.Add(new CalloutControl.CalloutItem(10, 1, 0, 100, 200, 100));
            vm.Groups[0].Group.Add(new CalloutControl.CalloutItem(10, 2, 100, 0, 100, 200));

            vm.Groups[1].Group.Add(new CalloutControl.CalloutItem(10, 1, 100, 0, 200, 100));
            vm.Groups[1].Group.Add(new CalloutControl.CalloutItem(10, 2, 100, 200, 200, 100));

            DataContext = vm;
        }
    }
}

namespace CalloutControl
{
    public class CalloutItem : INotifyPropertyChanged
    {
        public CalloutItem()
        {

        }
        public CalloutItem(int length,
                   int itemNum,
                     double _x1,
                    double _y1,
            double _x2,
            double _y2)
        {
            Length = length;
            ItemNum = itemNum;
            X1 = _x1;
            Y1 = _y1;
            X2 = _x2;
            Y2 = _y2;
        }
        private int length;

        public int Length
        {
            get { return length; }
            set
            {
                length = value;
                OnPropertyChanged("Length");
            }
        }
        private int itemNum;

        public int ItemNum
        {
            get { return itemNum; }
            set
            {
                itemNum = value;
                OnPropertyChanged("ItemNum");
            }
        }
        //public int      ItemNum;
        private double x1;
        public double X1
        {
            get { return x1; }
            set
            {
                x1 = value;
                OnPropertyChanged("X1");
            }
        }
        private double y1;
        public double Y1
        {
            get { return y1; }
            set
            {
                y1 = value;
                OnPropertyChanged("Y1");
            }
        }

        private double x2;
        public double X2
        {
            get { return x2; }
            set
            {
                x2 = value;
                OnPropertyChanged("X2");
            }
        }
        private double y2;
        public double Y2
        {
            get { return y2; }
            set
            {
                y2 = value;
                OnPropertyChanged("Y2");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
    public class CalloutGroup : INotifyPropertyChanged
    {
        ObservableCollection<CalloutItem> group = new ObservableCollection<CalloutItem>();
        public CalloutGroup(int nItems)
        {
            NumItems = nItems;

        }
        public ObservableCollection<CalloutItem> Group
        {
            get { return group; }
            set
            {
                group = value;
                OnPropertyChanged("Group");
            }
        }
        private double distributionHeight = 200;

        public double DistributionHeight
        {
            get { return distributionHeight; }
            set
            {
                distributionHeight = value;
                Redistribute();
                OnPropertyChanged("DistributionHeight");
            }
        }


        private void Redistribute()
        {
            double step = distributionHeight / numItems;
            double currY = step / 2;
            var redistArr = group.ToArray();

            for (int i = 0; i < group.Count(); i++)
            {
                redistArr[i].Y1 = currY;
                currY += step;
            }
            OnPropertyChanged("Group");
        }
        private int numItems = 10;

        public int NumItems
        {
            get { return numItems; }
            set
            {
                numItems = value;
                group.Clear();
                for (int i = 0; i < numItems; i++)
                {
                    //group.Add(new CalloutItem());
                }
                Redistribute();
                OnPropertyChanged("NumItems");
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }

    public class MainWindowViewModel : INotifyPropertyChanged
    {

        ObservableCollection<CalloutGroup> groups = new ObservableCollection<CalloutGroup>();

        public ObservableCollection<CalloutGroup> Groups
        {
            get { return groups; }
            set
            {
                groups = value;
                OnPropertyChanged("Groups");
            }
        }
        public MainWindowViewModel()
        {

        }


        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

XAML:

<Window.Resources>
    <DataTemplate x:Key="LineTemplate">
        <Line X1="{Binding X1}" X2="{Binding X2}"
              Y1="{Binding Y1}" Y2="{Binding Y2}"
              Stroke="Blue" 
                  StrokeThickness="10" />
    </DataTemplate>


    <DataTemplate x:Key="GroupTemplate">
        <Border BorderThickness="5" Background="Brown" BorderBrush="Red">
            <ItemsControl ItemsSource="{Binding Group}" 
                      ItemTemplate="{StaticResource LineTemplate}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                        <Canvas Background="Transparent" Width="200" Height="{Binding DistributionHeight}"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
        </Border>
    </DataTemplate>
</Window.Resources>
<Grid>
    <Border>
        <ListView ItemsSource="{Binding Groups}" ItemTemplate="{StaticResource GroupTemplate}">

        </ListView>
    </Border>
</Grid>