如何同步两个嵌套数据网格之间的列宽?

时间:2010-01-01 04:04:55

标签: wpf .net-3.5 datagrid binding

我有一个带有几列的wpf工具箱数据网格,然后在行详细信息中我有另一个数据网格。基本上我正在模拟treelistview控件(例如:http://www.codeproject.com/KB/list/treelistview.aspx)但使用datagrids。

我想将行详细信息中datagrid的列宽与主父数据网格的列宽同步。

我尝试像这样定义子数据网格列:

<toolkit:DataGridTextColumn Binding="{Binding Path=Name}" Width="{Binding ElementName=mainDataGrid, Path=Columns[0].ActualWidth}" />

这不起作用(即使有一些变体,如Mode = OneWay)。

编辑:

好的,我放弃让绑定工作。试用代码...... 现在,由于DataGrid不会触发更改列宽的事件,因此我自己创建了:

PropertyDescriptor pd = DependencyPropertyDescriptor.FromProperty(DataGridColumn.WidthProperty, typeof(DataGridColumn));
pd.AddValueChanged(testColumn, new EventHandler(mainDataGrid_WidthPropertyChanged));

private void mainDataGrid_WidthPropertyChanged(object sender, EventArgs e)
{
    // this works fine, but how do I find my templated child datagrid?
}

该事件似乎正确触发,但我似乎无法找到我的模板化数据网格。每行都有一个行详细信息部分,但可以隐藏部分或全部。但即使我的行详细信息可见,我也找不到对它的引用(总是为空)。

DataGrid dg = mainDataGrid.FindChild(null, typeof(DataGrid)) as DataGridRow; // dg always null

这是我使用的'FindChild'方法。 谁知道问题可能是什么?还是其他任何建议?感谢

4 个答案:

答案 0 :(得分:1)

一种选择是使用Grid而不是Datagrid。您可以在共享大小的各个列定义上使用SharedSizeGroup属性。

答案 1 :(得分:1)

使用这个Avalon(pre WPF)团队博客文章,我设法得到了一些有用的东西。我以为我已经用DataGrid实现了它,我搜索了我的代码并且没有提出任何结果。无论如何,如果你确定你会弄清楚,希望这会有所帮助。

http://blogs.msdn.com/atc_avalon_team/archive/2006/03/01/541206.aspx

答案 2 :(得分:0)

好的,我已经完成了这项工作,但我并不完全满意。问题是孩子没有被正确检测到。基本上我在未连接的位置手动钻取可视树(使用Mole来帮助我)。如果视觉树不同,这可能对其他人不起作用,但这是一个普遍的想法。这是我所做的粗略版本,但我仍然在查看它究竟发生了什么:

public MyWindow()
{
    InitializeComponent();
    PropertyDescriptor pd = DependencyPropertyDescriptor.FromProperty(DataGridColumn.WidthProperty, typeof(DataGridColumn));
    pd.AddValueChanged(testColumn, new EventHandler(dgMain_WidthPropertyChanged));
    // do the same for all columns
}

private void dgMain_WidthPropertyChanged(object sender, EventArgs e)
{
    SyncColumnWidths();
}

private void SyncColumnWidths() // put all this in a try..catch too
{
    ScrollContentPresenter scp = dgMain.FindChild(null, typeof(ScrollContentPresenter)) as ScrollContentPresenter;
    ItemsPresenter ip = scp.Content as ItemsPresenter;
    DataGridRowsPresenter dgrp = ip.FindChild(null, typeof(DataGridRowsPresenter)) as DataGridRowsPresenter;
    foreach (DataGridRow dgr in dgrp.Children)
    {
        if (dgr.DetailsVisibility == Visibility.Visible)
        {
            DataGrid dg = dgr.FindChild(null, typeof(DataGrid)) as DataGrid; // child datagrid
            if (dg != null)
            {
                for (int i = 0; i < dgMain.Columns.Count; i++)
                    dg.Columns[i].Width = dgMain.Columns[i].ActualWidth;
            }
        }
    }
}

答案 3 :(得分:0)

我知道这是一个老问题(从2010年开始),但这是我如何解决同样的问题。本质上,我在后面的代码中创建了对所有嵌套ListView的引用,然后在我的父“列”(在我的例子中,使用网格创建的虚拟列,但同样的原则适用时)更新它们的宽度宽度有变化。

注意 - 在XAML中,我将ListView_Loaded指定为子(嵌套)列表视图的Loaded事件的处理程序。

忽略我的父列更改事件是GridSplitter_DragDelta的事实,这是因为我使用GridSplitters“伪造”顶级标题行;在你的情况下,你将获得在你自己的事件处理程序中移动的列的宽度,然后使用linq语句“childViewColumns.ForEach((gvcc)=&gt; gvcc [index] .Width”等分配它。

公共部分类SomeThing:UserControl

private List<GridViewColumnCollection> childViewColumns = new List<GridViewColumnCollection>();

        private void ListView_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
            GridView gv = ((ListView)sender).View as GridView;
            childViewColumns.Add(gv.Columns);
        }

        private void GridSplitter_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            GridSplitter gs = sender as GridSplitter;
            Grid g = gs.Parent as Grid;
            int index = Grid.GetColumn(gs);
            double w = g.ColumnDefinitions[index].Width.Value;
            childViewColumns.ForEach((gvcc) => gvcc[index].Width = w);

        }

}