具有自定义面板和项容器的WPF嵌套项控件

qvtsj1bj  于 2022-12-14  发布在  其他
关注(0)|答案(1)|浏览(172)

我正在创建一个基本的甘特,作为事件日程的可视化表示。为此,我有一个ItemsControl来呈现StackPanel中的日程行项目。在该“父”ItemsControl中,我有另一个ItemsControl来呈现甘特图视图-基本上只是形状。如下所示:

<ItemsControl ItemsSource="{Binding ScheduleLines}"
                      Grid.Row="1"
                      Height="100">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>

            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="100"/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>

                        <TextBlock Text="{Binding Name}"
                                   Grid.Column="0"/>

                        <ItemsControl ItemsSource="{Binding Events}"
                                      Grid.Column="1">

                            <ItemsPanelTemplate>
                                <components:ScheduleRowPanel/>
                            </ItemsPanelTemplate>

                            <ItemContainerTemplate>
                                <scheduleitems:ScheduleEventElement EventDate="{Binding EventDate}"
                                                                    Status="{Binding Status}"/>
                            </ItemContainerTemplate>

                        </ItemsControl>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

这个视图的datacontext有一个名为ScheduleLinesObservableCollectionScheduleLines的每个项都有另一个Events的可观察集合。
在子ItemsControl中,我有一个自定义面板,用于安排事件:

public class ScheduleRowPanel : Panel
    {
        //Scale and MinDate are dependency properties on this custom panel

        protected override Size ArrangeOverride(Size finalSize)
        {
            foreach(UIElement child in Children)
            {
                ArrangeChild(child, MinDate, Scale, finalSize.Height);
            }

            return finalSize;
        }

        private void ArrangeChild(UIElement child, DateOnly minDate, double scale, double panelHeight)
        {
            if (child.GetType() == typeof(ScheduleEventElement))
            {
                ScheduleEventElement eventElement = (ScheduleEventElement)child;
                DateOnly eventDate = eventElement.EventDate;

                double xoffset = scale * (eventDate.DayNumber - minDate.DayNumber);
                double yoffset = panelHeight / 2;

                child.Arrange(new Rect(xoffset, yoffset, 50, 50));
            }
            else
            {
                throw new InvalidOperationException("Have not implemented any other type of schedule entity");
            }
        }

    }

面板会排列下列事件,这些事件是具有填色的旋转矩形:

public class ScheduleEventElement : FrameworkElement
    {

        public DateOnly EventDate
        {
            get { return (DateOnly)GetValue(EventDateProperty); }
            set { SetValue(EventDateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for EventDate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EventDateProperty =
            DependencyProperty.Register("EventDate", typeof(DateOnly), typeof(ScheduleEventElement), new PropertyMetadata(DateOnly.FromDayNumber(1)));

        public EventStatus Status
        {
            get { return (EventStatus)GetValue(StatusProperty); }
            set { SetValue(StatusProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Status.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StatusProperty =
            DependencyProperty.Register("Status", typeof(EventStatus), typeof(ScheduleEventElement), new PropertyMetadata(EventStatus.Scheduled));

        protected override void OnRender(DrawingContext drawingContext)
        {
            RectangleGeometry rectangle = new RectangleGeometry();
            SolidColorBrush fill = new SolidColorBrush();

            rectangle.Rect = new Rect(0, 0, 10, 0);

            RotateTransform rotate = new RotateTransform();
            rotate.CenterX = 0.5;
            rotate.CenterY = 0.5;
            rotate.Angle = 45;

            rectangle.Transform = rotate;

            switch (Status)
            {
                case EventStatus.Scheduled:
                    fill.Color = (Color)ColorConverter.ConvertFromString("#262626");
                    break;
                case EventStatus.Early:
                    fill.Color = (Color)ColorConverter.ConvertFromString("#009d9a");
                    break;
                case EventStatus.Late:
                    fill.Color = (Color)ColorConverter.ConvertFromString("#6929c4");
                    break;
            }

            drawingContext.DrawGeometry(fill, null, rectangle);
        }

    }

运行嵌套的ItemControl时出现以下错误:

我理解这是因为我需要将内部ItemControl修改为ItemsSource = {Binding Events},而不是<ItemsControl> <ItemsControl.ItemsSource/>,但我不确定如何使用该语法指定项源。我的理解正确吗?如果正确,正确的语法是什么?
另外,我有ItemsContainerTemplate的正确实现吗?或者这应该在ItemsTemplate中吗?
谢谢

dced5bon

dced5bon1#

不能只将<ItemsPanelTemplate><ItemContainerTemplate>写入<ItemsControl>标记中,需要将它们写入相关属性标记中:<ItemsControl.ItemsPanel><ItemsControl.ItemTemplate>中的至少一个。

<ItemsControl ItemsSource="{Binding Events}"
              Grid.Column="1">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <components:ScheduleRowPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <scheduleitems:ScheduleEventElement EventDate="{Binding EventDate}"
                                                Status="{Binding Status}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

相关问题