ItemsControl在MainWindow的构造函数中没有子节点

时间:2012-01-04 02:16:28

标签: wpf itemscontrol mainwindow visualtreehelper itemspaneltemplate

根据SO问题“WPF: arranging collection items in a grid”的答案,我有以下内容:

    <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());

为此,当然,我需要找到网格。我在问题WPF ways to find controls中使用了CrimsonX的FindChild来首先找到itemsControl1,然后使用它作为父级,找到网格。

    Grid FindTheGrid()
    {

            ItemsControl ic = (ItemsControl)this.FindName("itemsControl1");
            Grid theGrid = FindChild<Grid>(ic, "theGrid");

    }

从按钮的单击事件处理程序调用时,此方法有效。但是,当从MainWindow的构造函数调用它时失败,因为ic的childrenCount为0。

int childrenCount = VisualTreeHelper.GetChildrenCount(theParent);

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

2 个答案:

答案 0 :(得分:2)

WPF在后台为ItemsControl的项目(通常是DataTemplate)生成“容器”,它们将不会立即可用。

了解项目何时可用的唯一方法是订阅ItemsControl的ItemContainerGenerator属性上的StatusChanged事件:

itemsControl1.ItemContainerGenerator.StatusChanged += ic_GeneratorStatusChanged;

...然后从事件处理程序中取消订阅,因为你只需要它来触发一次:

void ic_GeneratorStatusChanged(object sender, EventArgs e)
{

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

    itemsControl1.ItemContainerGenerator.StatusChanged -= ic_GeneratorStatusChanged;

    // your items are now generated
}

这是一种迂回的做事方式,当然,但这是了解ItemsControl的项目存在于可视化树中的唯一方法。

答案 1 :(得分:1)

我厌倦了为我的网格写出RowDefinitionsColumnDefinitions,因此创建了一些自定义的DependencyProperties,可以让你指定网格定义中的行数/列数。

可以找到依赖项属性的代码here,并按如下方式使用:

<Grid local:GridHelpers.RowCount="{Binding RowCount}"
      local:GridHelpers.ColumnCount="{Binding ColumnCount}" />

如果它给你一个关于绑定的错误,那么将DependencyProperty定义中的typeof(Grid)更改为typeof(GridHelpers)。我的第一个帮助类版本不允许绑定,我不记得我发布了哪一个。

修改

以下是我正在使用的代码,包括在SomeInt更改时正确更新UI。我在单击按钮

时测试切换SomeInt在2和3之间

<强> XAML

<Grid ShowGridLines="True"
      local:GridProperties.ColumnCount="{Binding SomeInt}"
      local:GridProperties.RowCount="{Binding SomeInt}">

    <TextBox Text="Test" Grid.Row="0" Grid.Column="0" />
    <TextBox Text="Test" Grid.Row="0" Grid.Column="1" />
    <TextBox Text="Test" Grid.Row="0" Grid.Column="2" />
    <TextBox Text="Test" Grid.Row="1" Grid.Column="0" />
    <TextBox Text="Test" Grid.Row="1" Grid.Column="1" />
    <TextBox Text="Test" Grid.Row="1" Grid.Column="2" />
    <TextBox Text="Test" Grid.Row="2" Grid.Column="0" />
    <TextBox Text="Test" Grid.Row="2" Grid.Column="1" />
    <TextBox Text="Test" Grid.Row="2" Grid.Column="2" />
</Grid>

<强>的DependencyProperty

public class GridProperties
{
    #region RowCount Property

    /// <summary>
    /// Adds the specified number of Rows to RowDefinitions. Default Height is Auto
    /// </summary>
    public static readonly DependencyProperty RowCountProperty =
        DependencyProperty.RegisterAttached("RowCount", typeof(int),
        typeof(GridProperties),
        new PropertyMetadata(-1, RowCountChanged));

    // Get
    public static int GetRowCount(DependencyObject obj)
    {
        return (int)obj.GetValue(RowCountProperty);
    }

    // Set
    public static void SetRowCount(DependencyObject obj, int value)
    {
        obj.SetValue(RowCountProperty, value);
    }

    // Change Event - Adds the Rows
    public static void RowCountChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (!(obj is Grid) || (int)e.NewValue < 0)
            return;

        Grid grid = (Grid)obj;
        grid.RowDefinitions.Clear();

        for (int i = 0; i < (int)e.NewValue; i++)
            grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });

        //SetStarRows(grid);
    }

    #endregion

    #region ColumnCount Property

    /// <summary>
    /// Adds the specified number of Columns to ColumnDefinitions. Default Width is Auto
    /// </summary>
    public static readonly DependencyProperty ColumnCountProperty =
        DependencyProperty.RegisterAttached("ColumnCount", typeof(int),
        typeof(GridProperties),
        new PropertyMetadata(-1, ColumnCountChanged));

    // Get
    public static int GetColumnCount(DependencyObject obj)
    {
        return (int)obj.GetValue(ColumnCountProperty);
    }

    // Set
    public static void SetColumnCount(DependencyObject obj, int value)
    {
        obj.SetValue(ColumnCountProperty, value);
    }

    // Change Event - Add the Columns
    public static void ColumnCountChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (!(obj is Grid) || (int)e.NewValue < 0)
            return;

        Grid grid = (Grid)obj;
        grid.ColumnDefinitions.Clear();

        for (int i = 0; i < (int)e.NewValue; i++)
            grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });

        // SetStarColumns(grid);
    }

    #endregion
}

<强>结果

Example1 Example2