0

这是ItemsControl 在 MainWindow 的构造函数期间没有子项的后续操作

根据对 SO 问题“WPF:在网格中排列集合项目”的回答,我有以下内容:

 <ItemsControl Name="itemsControl1" ItemsSource="{Binding MyItems}"> 
    <ItemsControl.ItemsPanel> 
        <ItemsPanelTemplate> 
            <Grid Name="theGrid" ShowGridLines="True" /> 
        </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.ItemContainerStyle> 
        <Style TargetType="{x:Type FrameworkElement}"> 
            <Setter Property="Grid.Row" Value="{Binding RowIndex}" /> 
            <Setter Property="Grid.Column" Value="{Binding ColumnIndex}" /> 
        </Style> 
    </ItemsControl.ItemContainerStyle> 
</ItemsControl> 

现在,我想在后面的代码中设置 theGrid 的行数和列数:theGrid.RowDefinitions.Clear(); theGrid.ColumnDefinitions.Clear();

        for (uint i = 0; i < theNumberOfRows; i++) 
            theGrid.RowDefinitions.Add(new RowDefinition()); 

        for (uint i = 0; i < theNumberOfCols; i++) 
            theGrid.ColumnDefinitions.Add(new ColumnDefinition()); 

根据MattHamilton的回答,网格在 itemsControl1 后可用。ItemContainerGenerator.StatusChanged 以 GeneratorStatus.ContainersGenerated 的状态触发。

但是,尝试从事件处理程序修改网格会引发“无法在只读状态下修改 'RowDefinitionCollection'”异常。

那么,如何在窗口显示给用户之前设置 theGrid 的行和列集合?

编辑:我正在从 itemsControl1.ItemContainerGenerator.StatusChanged 事件处理程序修改网格的属性:

        if (itemsControl1.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
            return;

        itemsControl1.ItemContainerGenerator.StatusChanged -= ItemContainerGeneratorStatusChanged;

        SetGridRowsAndColumns(InitialNumberOfRows, InitialMaxNumberOfCols);

请注意,SetGridRowsAndColumns(numberOfRows, numberOfCols) 稍后会起作用,以响应按钮单击。

4

2 回答 2

0

我将使用附加行为而不是 ItemsControl 的低级自定义。

如果您只需要一个矩阵控件 - 您可以考虑使用行 Grid 而不是 ItemsControl(这就是我们最终得到的)。ItemsControl 是无限强大的生物,但有时它可能是一个挑战,通过它的声音设计来挤压一个小而有用的额外未来。

按照这种方法,您必须进行的更改是: 1. 使用 Dimension 并将其绑定到您想要的 Size。2. 创建一个自定义 ItemTemplate 并将 GridEx.Position 添加到其根视觉绑定到相关的 Point 属性。

关于这两个,请给我们留言,我会用更多细节更新我的答案。

这是课程:

public class GridEx
    {
        public static DependencyProperty DimensionProperty =
            DependencyProperty.Register("Dimension",
            typeof(Size),
            typeof(Grid),
            new PropertyMetadata((o, e) => 
            {
                GridEx.OnDimensionChanged((Grid)o, (Size)e.NewValue);
            }));

        public static DependencyProperty PositionProperty =
            DependencyProperty.Register("Position",
            typeof(Point),
            typeof(UIElement),
            new PropertyMetadata((o, e) =>
            {
                GridEx.OnPostionChanged((UIElement)o, (Point)e.NewValue);
            }));

        private static void OnDimensionChanged(Grid grid, Size resolution)
        {
            grid.RowDefinitions.Clear();
            grid.ColumnDefinitions.Clear();

            for (int i = 0; i < resolution.Width; i++)
            {
                grid.ColumnDefinitions.Add(new ColumnDefinition());
            }

            for (int i = 0; i < resolution.Height; i++)
            {
                grid.RowDefinitions.Add(new RowDefinition());
            }
        }

        private static void OnPostionChanged(UIElement item, Point position)
        {
            Grid.SetColumn(item, Convert.ToInt32((position.X)));
            Grid.SetRow(item, Convert.ToInt32(position.Y));
        }

        public static void SetDimension(Grid grid, Size dimension)
        {
            grid.SetValue(GridEx.DimensionProperty, dimension);
        }

        public static Size GetDimension(Grid grid)
        {
            return (Size)grid.GetValue(GridEx.DimensionProperty);
        }

        public static void SetPosition(UIElement item, Point position)
        {
            item.SetValue(GridEx.PositionProperty, position);
        }

        public static Point GetPosition(Grid grid)
        {
            return (Point)grid.GetValue(GridEx.PositionProperty);
        }
    }

以下是我们如何使用它:

<Window x:Class="GridDefs.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:GridDefs"
        Title="MainWindow" Height="350" Width="525">
    <Grid local:GridEx.Dimension="3,3">
        <Button local:GridEx.Position="0,0">A</Button>
        <Button local:GridEx.Position="1,1">A</Button>
        <Button local:GridEx.Position="2,2">A</Button>
    </Grid>
</Window>
于 2012-01-04T13:49:06.920 回答
0

以下是如何在不使用 ItemsControl 的情况下创建矩阵的方法,请注意,您属于主要内容 - 为项目指定模板的能力。

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 GridDefs
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            //
            this.DataContext = this; // alterantively use RelativeSource
        }

        public IEnumerable<Item> MyItems
        {
            get
            {
                List<Item> items = new List<Item>(3);

                items.Add(Item.Create("A1", new Point(0, 0)));
                items.Add(Item.Create("B2", new Point(1, 1)));
                items.Add(Item.Create("C3", new Point(2, 2)));

                return items;
            }
        }
    }

    public interface IMatrixItem
    {
        Point Position { get; }
    }

    // Model, note - it has to implement INotifyPropertyChanged if
    // you want to propagate its changes up to the UI
    public class Item: IMatrixItem
    {
        public static Item Create(string text,
            Point position)
        {
            Item item = new Item();

            item.Text = text;
            item.Position = position;

            return item;
        }

        public string Text
        {
            get;
            private set;
        }

        public Point Position
        {
            get;
            private set;
        }
    }

    public class GridEx
    {
        public static DependencyProperty DimensionProperty =
            DependencyProperty.RegisterAttached("Dimension",
            typeof(Size),
            typeof(GridEx),
            new PropertyMetadata(new Size(0, 0),
                (o, e) =>
                {
                    GridEx.OnDimensionChanged((Grid)o, (Size)e.NewValue);
                }));

        public static DependencyProperty PositionProperty =
            DependencyProperty.RegisterAttached("Position",
            typeof(Point),
            typeof(GridEx),
            new FrameworkPropertyMetadata(new Point(-1, -1),
                (o, e) =>
                {
                    GridEx.OnPostionChanged((UIElement)o, (Point)e.NewValue);
                }));

        public static DependencyProperty ItemStyleProperty =
           DependencyProperty.RegisterAttached("ItemStyle",
           typeof(Style),
           typeof(GridEx));

        public static DependencyProperty ItemsProperty =
            DependencyProperty.RegisterAttached("Items",
            typeof(IEnumerable<IMatrixItem>),
            typeof(GridEx),
            new PropertyMetadata((o, e) =>
            {
                GridEx.OnItemsChanged((Grid)o, (IEnumerable<IMatrixItem>)e.NewValue);
            }));

        #region "Dimension"

        private static void OnDimensionChanged(Grid grid, Size resolution)
        {
            grid.RowDefinitions.Clear();
            grid.ColumnDefinitions.Clear();

            for (int i = 0; i < resolution.Width; i++)
            {
                grid.ColumnDefinitions.Add(new ColumnDefinition());
            }

            for (int i = 0; i < resolution.Height; i++)
            {
                grid.RowDefinitions.Add(new RowDefinition());
            }
        }

        public static void SetDimension(Grid grid, Size dimension)
        {
            grid.SetValue(GridEx.DimensionProperty, dimension);
        }

        public static Size GetDimension(Grid grid)
        {
            return (Size)grid.GetValue(GridEx.DimensionProperty);
        }

        #endregion

        #region "Position"


        private static void OnPostionChanged(UIElement item, Point position)
        {
            item.SetValue(Grid.ColumnProperty, Convert.ToInt32(position.X));
            item.SetValue(Grid.RowProperty, Convert.ToInt32(position.Y));
        }

        private static T GetParentOfType<T>(DependencyObject current)
          where T : DependencyObject
        {
            for (DependencyObject parent = VisualTreeHelper.GetParent(current);
                parent != null;
                parent = VisualTreeHelper.GetParent(parent))
            {
                T result = parent as T;

                if (result != null)
                    return result;
            }

            return null;
        }

        public static void SetPosition(UIElement item, Point position)
        {
            item.SetValue(GridEx.PositionProperty, position);
        }

        public static Point GetPosition(UIElement grid)
        {
            return (Point)grid.GetValue(GridEx.PositionProperty);
        }

        #endregion

        #region "ItemStyle"

        public static void SetItemStyle(Grid item, Style style)
        {
            item.SetValue(GridEx.ItemStyleProperty, style);
        }

        public static Style GetItemStyle(Grid grid)
        {
            return (Style)grid.GetValue(GridEx.ItemStyleProperty);
        }

        #endregion

        #region "Items"

        private static void OnItemsChanged(Grid grid, IEnumerable<IMatrixItem> items)
        {
            grid.Children.Clear();

            // template
            Style style = GetItemStyle(grid);

            foreach (IMatrixItem item in items)
            {
                Control itemControl = new Control();

                grid.Children.Add(itemControl);

                itemControl.Style = style;
                itemControl.DataContext = item;

            }
        }

        public static void SetItems(Grid grid, IEnumerable<IMatrixItem> items)
        {
            grid.SetValue(GridEx.ItemsProperty, items);
        }

        public static IEnumerable<IMatrixItem> GetItems(Grid grid)
        {
            return (IEnumerable<IMatrixItem>)grid.GetValue(GridEx.ItemsProperty);
        }

        #endregion
    }
}

标记:

<Window x:Class="GridDefs.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:GridDefs"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style TargetType="Control" x:Key="t">
            <Setter Property="local:GridEx.Position" Value="{Binding Position}"></Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Button Content="{Binding Text}" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

    </Window.Resources>

    <Grid local:GridEx.Dimension="3,3" 
          local:GridEx.ItemStyle="{StaticResource t}"
          local:GridEx.Items="{Binding MyItems}">
    </Grid>
</Window>
于 2012-01-04T15:38:00.780 回答