【问题标题】:Modifying an ItemsPanel's Grid RowDefinitionCollection修改 ItemsPanel 的 Grid RowDefinitionCollection
【发布时间】:2012-01-04 13:18:02
【问题描述】:

这是ItemsControl has no children during MainWindow's constructor的后续行动

基于对 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'”异常。

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

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

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

        itemsControl1.ItemContainerGenerator.StatusChanged -= ItemContainerGeneratorStatusChanged;

        SetGridRowsAndColumns(InitialNumberOfRows, InitialMaxNumberOfCols);

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

【问题讨论】:

  • 嗨 Avi,您究竟是从哪里修改 Grid Row/Col Defs 的?
  • 嗨,德米特里。添加了解释这一点的编辑。

标签: wpf grid itemscontrol itemspanel itemspaneltemplate


【解决方案1】:

我会使用附加行为而不是 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>

【讨论】:

    【解决方案2】:

    以下是在不使用 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>
    

    【讨论】:

      猜你喜欢
      • 2011-01-20
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      • 2016-06-22
      • 2015-12-05
      • 2011-10-23
      • 2019-06-27
      • 1970-01-01
      相关资源
      最近更新 更多