Изменение сетки ItemsPanel RowDefinitionCollection - PullRequest
0 голосов
/ 04 января 2012

Это продолжение для 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 до того, как окно будет показано пользователю?

edit : я изменяю свойства сетки из itemsControl1.ItemContainerGenerator.StatusChanged обработчик события:

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

        itemsControl1.ItemContainerGenerator.StatusChanged -= ItemContainerGeneratorStatusChanged;

        SetGridRowsAndColumns(InitialNumberOfRows, InitialMaxNumberOfCols);

Обратите внимание, что SetGridRowsAndColumns (numberOfRows, numberOfCols) работает позже, в ответ на нажатие кнопки.

Ответы [ 2 ]

0 голосов
/ 04 января 2012

Вот как вы можете создать матрицу без использования 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>
0 голосов
/ 04 января 2012

Я бы использовал прикрепленное поведение в отличие от низкоуровневой настройки для ItemsControl.

Если все, что вам нужно, это матричный элемент управления - вы можете рассмотреть возможность использования Grid для строк вместо ItemsControl (с этим мы и столкнулись). ItemsControl - безгранично мощное существо, но иногда это может быть проблемой, чтобы выжать маленькое, но полезное дополнительное будущее благодаря своему звуковому дизайну.

Изменения, которые вы должны будете сделать, используя этот подход: 1. Используйте Dimension и привяжите его к размеру, который вы хотите. 2. Создайте пользовательский шаблон ItemTemplate и добавьте GridEx.Position к его корневому визуальному объекту, связанному со свойством Relvant 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>
...