2012-01-04 4 views
0

Это Followup для ItemsControl has no children during MainWindow's constructorИзменение ItemsPanel в Грид RowDefinitionCollection

на основе ответа на 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> 

Теперь, Я хочу установить количество строк и столбцов Grid в коде позади: 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 «s ответ там, то ГИРД предоставляется один раз itemsControl1. ItemContainerGenerator.StatusChanged пожары со статусом GeneratorStatus.ContainersGenerated.

Однако попытка изменить сетку из обработчика события вызывает исключение «Невозможно изменить« RowDefinitionCollection »в состоянии« только для чтения ».

Итак, как я могу установить коллекцию строк и столбцов Grid перед тем, как окно будет показано пользователю?

редактировать: Я изменение свойств сетке от itemsControl1.ItemContainerGenerator.StatusChanged обработчика событий:

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

     itemsControl1.ItemContainerGenerator.StatusChanged -= ItemContainerGeneratorStatusChanged; 

     SetGridRowsAndColumns(InitialNumberOfRows, InitialMaxNumberOfCols); 

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

+0

Привет Avi, где именно вы модифицируя свои сетки Row/Col Defs от? –

+0

Привет, Дмитрий. Добавлено редактирование, объясняющее это. – Avi

ответ

0

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

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

Изменения, которые вы должны будете сделать, следуя этому подходу: 1. Используйте размер и привяжите его к размеру, который вы хотите. 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> 
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 
    } 
} 

Markup:

<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>