WPF:绑定数据网格标题宽度

ted*_*dy2 0 c# wpf binding

我试图将一个数据网格的标题宽度绑定到另一个数据网格的标题.

所以,我为父数据网格的每一行添加了一个数据网格.现在,我试图使用Parent标头的列控制子数据网格的列大小.

所以在最后一列的headertemplate中,我添加了一个只有列标题的数据网格,没有行.在本专栏的celltemplate中,我添加了另一个数据网格,没有标题,只有数据行.

在调整headertemplate datagrid列标题的大小时,XAML中是否有任何方法可以调整celltemplate的datagrid列的大小.

在SO上读了很多关于CodeProject等的帖子,但是我无法使它工作.有可能吗?

XAML

 <Grid>
            <DataGrid x:Name="Test"
                      AutoGenerateColumns="False"
                      CanUserAddRows="False"
                      ItemsSource="{Binding AllAssets}"
                      CanUserResizeColumns="True">
                <DataGrid.Resources>               
                    <DataTemplate x:Key="NewKey2">
                        <DataGrid Name="dgC"
                                  AutoGenerateColumns="False"
                                  HeadersVisibility="None"
                                  ItemsSource="{Binding months}"
                                  CanUserResizeColumns="True">
                            <DataGrid.Columns>
                                <DataGridTextColumn x:Name="Col1" Binding="{Binding value}" />
                                <DataGridTextColumn x:Name="Col2" Binding="{Binding MonthName}" />
                            </DataGrid.Columns>
                        </DataGrid>
                    </DataTemplate>
                    <DataTemplate x:Key="NewKey3">
                        <StackPanel>
                            <Label HorizontalAlignment="Center">All Headers</Label>
                            <DataGrid Name="dgH">
                                <DataGrid.Columns>
                                    <DataGridTextColumn Width="{Binding ElementName=Col1, Path=ActualWidth}" Header="Value" />
                                    <DataGridTextColumn Width="{Binding ElementName=Col2, Path=ActualWidth}" Header="Month" />
                                    <!--Error or no result on these attempts
                                    <DataGridTextColumn Header="Month" Width="{Binding Source={x:Reference Col2}, Path=ActualWidth}"/>--><!--
                                    <DataGridTextColumn >
                                        <DataGridTextColumn.Header>
                                            <TextBlock Width="{Binding Source={x:Reference Col1}, Path=ActualWidth}" >Value</TextBlock>
                                        </DataGridTextColumn.Header>
                                    </DataGridTextColumn>
                                    <DataGridTextColumn  Header="Month" />-->
                                </DataGrid.Columns>
                            </DataGrid>
                        </StackPanel>
                    </DataTemplate>
                </DataGrid.Resources>
                <DataGrid.Columns>
                    <DataGridTemplateColumn Header="Id">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Label Content="{Binding id}" />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn Header="Name">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Label Content="{Binding name}" />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn CellTemplate="{StaticResource NewKey2}"
                                            HeaderTemplate="{StaticResource NewKey3}" />
                </DataGrid.Columns>

            </DataGrid>
        </Grid>
Run Code Online (Sandbox Code Playgroud)

C#类数据例如:

namespace WpfApplication1
{
    public class Assets
    {
        public List<Asset> AllAssets { get; set; }

        public Assets()
        {
            AllAssets = new List<Asset>();

            for (int i = 1; i < 3; i++)
            {
                Asset asset = new Asset();

                asset.id = i;
                asset.name = "asset " + i.ToString();

                for (int x = 1; x < 3; x++)
                {
                    MonthsData months = new MonthsData();
                    months.MonthName = "Month " + x.ToString();
                    months.value = x;
                    asset.months.Add(months);
                }

                AllAssets.Add(asset);
            }
        }

    }

    public class Asset
    {
        public int id { get; set; }
        public string name { get; set; }
        public List<MonthsData> months { get; set; }

        public Asset()
        {
            months = new List<MonthsData>();
        }
    }

    public class MonthsData 
    {
        public string MonthName { get; set; }
        public int value { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

小智 5

假设您可以在ViewModel中定义几个属性

public class Assets : MVVM.ViewModel.ViewModelBase
{
    public List<Asset> AllAssets { get; set; }
    private double col1Width;
    private double col2Width;
    public double Col1Width
    {
        get { return col1Width; }
        set { col1Width = value; OnPropertyChanged("Col1Width"); }
    }
    public double Col2Width
    {
        get { return col2Width; }
        set { col2Width = value; OnPropertyChanged("Col2Width"); }
    }
Run Code Online (Sandbox Code Playgroud)

然后,您将能够通过帮助程序从XAML读取Load事件的实际宽度

    private void Grid_Loaded(object sender, RoutedEventArgs e)
    {
        var dg = FindVisualChildByName<DataGrid>(Test, "dgC");
        assets.Col1Width = dg.Columns[0].ActualWidth;
        assets.Col2Width = dg.Columns[1].ActualWidth;

    }
Run Code Online (Sandbox Code Playgroud)

并将它们从网格的DataContext中设置回XAML绑定

                            <DataGridTextColumn Header="Value" >
                                <DataGridTextColumn.HeaderStyle>
                                    <Style TargetType="DataGridColumnHeader">
                                        <Setter Property="Width" Value="{Binding ElementName=Test, Path=DataContext.Col1Width, UpdateSourceTrigger=PropertyChanged}"/>
                                    </Style>
                                </DataGridTextColumn.HeaderStyle>
                            </DataGridTextColumn>
                            <DataGridTextColumn Header="Month" >
                                <DataGridTextColumn.HeaderStyle>
                                    <Style TargetType="DataGridColumnHeader">
                                        <Setter Property="Width" Value="{Binding ElementName=Test, Path=DataContext.Col2Width, UpdateSourceTrigger=PropertyChanged}"/>
                                    </Style>
                                </DataGridTextColumn.HeaderStyle>
                            </DataGridTextColumn>
Run Code Online (Sandbox Code Playgroud)

回复评论

正如下面的评论中正确指出的那样,我们可以避免"仅与ViewModel中的View相关的属性"并管理任意(但固定)数量的列,以便dgC和dgH的宽度(假设它们具有相同的宽度)列数)是链接的

    private void Grid_Loaded(object sender, RoutedEventArgs e)
    {
        var dgC = FindVisualChildByName<DataGrid>(Test, "dgC");
        var dgH = FindVisualChildByName<DataGrid>(Test, "dgH");
        for (int i = 0; i < dgC.Columns.Count; i++)
        {
            dgH.Columns[i].Width = dgC.Columns[i].ActualWidth;
        }

    }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,不再需要VM绑定

                            <DataGridTextColumn Header="Value" />
                            <DataGridTextColumn Header="Month" />
Run Code Online (Sandbox Code Playgroud)

管理列大小调整(如果不需要,请跳过此列)

这更复杂,所以请在严格要求的情况下继续.

让我们更改实用程序,以便它将返回所有datagrid dgCs(每行有一个dgC)

    public static IEnumerable<T> FindVisualChildByName<T>(DependencyObject parent, string name) where T : DependencyObject
    {
        List<T> list = new List<T>();
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);
            string controlName = child.GetValue(Control.NameProperty) as string;
            if (controlName == name)
            {
                list.Add(child as T);
            }
            else
            {
                IEnumerable<T> result = FindVisualChildByName<T>(child, name);
                if (result != null)
                    list.AddRange(result);
            }
        }
        return list;
    }
Run Code Online (Sandbox Code Playgroud)

现在我们将为实际的宽度变化定义一个依赖属性

    private bool _columnWidthChanging;
    private void ColumnWidthPropertyChanged(object sender, EventArgs e)
    {
        // listen for when the mouse is released
        _columnWidthChanging = true;
        if (sender != null)
            Mouse.AddPreviewMouseUpHandler(this, BaseDataGrid_MouseLeftButtonUp);
    }

    void BaseDataGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (_columnWidthChanging)
        {
            _columnWidthChanging = false;
            var dgCs = FindVisualChildByName<DataGrid>(Test, "dgC");
            var dgH = FindVisualChildByName<DataGrid>(Test, "dgH").First();
            foreach (var dgC in dgCs)
            {
                for (int i = 0; i < dgC.Columns.Count; i++)
                {

                    var column = dgH.Columns[i];
                    dgC.Columns[i].Width = column.ActualWidth;
                }
            }
        }
    }

    private void Grid_Loaded(object sender, RoutedEventArgs e)
    {
        var dgC = FindVisualChildByName<DataGrid>(Test, "dgC").First();
        var dgH = FindVisualChildByName<DataGrid>(Test, "dgH").First();
        for (int i = 0; i < dgC.Columns.Count; i++)
        {
            var column = dgC.Columns[i];
            dgH.Columns[i].Width = column.ActualWidth;

            PropertyDescriptor pd = DependencyPropertyDescriptor
                         .FromProperty(DataGridColumn.ActualWidthProperty,
                                       typeof(DataGridColumn));

                //Add a listener for this column's width
                pd.AddValueChanged(dgH.Columns[i],
                                   new EventHandler(ColumnWidthPropertyChanged));


        }
Run Code Online (Sandbox Code Playgroud)