繁体   English   中英

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

[英]WPF: Binding Data Grid Header Width

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

因此,我为父数据网格的每一行添加了一个数据网格。 现在,我尝试使用“父”标头的列控制子数据网格的列大小。

因此,在最后一列的标题模板中,我添加了一个仅具有列标题而没有行的数据网格。 在本专栏的单元模板中,我添加了另一个数据网格,没有标题,只有数据行。

当我调整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>

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

在此处输入图片说明

假设您可以在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"); }
    }

那么您将能够通过助手从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;

    }

并将它们从网格的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>

回复评论

正如下面的注释中正确指出的那样,我们可以避免“仅与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;
        }

    }

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

                            <DataGridTextColumn Header="Value" />
                            <DataGridTextColumn Header="Month" />

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

这比较复杂,因此,只有在严格要求时才继续操作。

让我们更改该实用程序,以便它将返回所有datagrid dgC(每行有一个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;
    }

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

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


        }

您可以使用一个Grid ,并设置SharedSizeGroup财产ColumnDefinition 这将“自动”调整Grid.IsSharedSizeScope定义的列的Grid.IsSharedSizeScope

如果您想了解有关此内置功能的更多信息,可以在Google上进行搜索或查看: https : //wpf.2000things.com/tag/sharedsizegroup/

我采用了您的代码以使其正常工作。 我取代了DataGrid页眉/细胞模板,用一Grid为了使用

XAML

<Grid Grid.IsSharedSizeScope="True">
<DataGrid AutoGenerateColumns="False"
            CanUserAddRows="False"
            ItemsSource="{Binding AllAssets}"
            CanUserResizeColumns="True">
    <DataGrid.Resources>
        <DataTemplate x:Key="NewKey2">
            <ItemsControl ItemsSource="{Binding months}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid ShowGridLines="True">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition SharedSizeGroup="A" />
                                <ColumnDefinition SharedSizeGroup="B" />
                            </Grid.ColumnDefinitions>
                            <TextBlock Text="{Binding value}"
                                        Margin="5" />
                            <TextBlock Text="{Binding MonthName}"
                                        Margin="5"
                                        Grid.Column="2" />
                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DataTemplate>
        <DataTemplate x:Key="NewKey3">
            <StackPanel>
                <Label HorizontalAlignment="Center">All Headers</Label>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition SharedSizeGroup="A" />
                        <ColumnDefinition SharedSizeGroup="B" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="Value"
                                Margin="5" />
                    <TextBlock Text="Month"
                                Margin="5"
                                Grid.Column="1" />
                </Grid>
            </StackPanel>
        </DataTemplate>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Id">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Label Content="{Binding id}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Name"
                                Width="Auto">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Label Content="{Binding name}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn CellTemplate="{StaticResource NewKey2}"
                                HeaderTemplate="{StaticResource NewKey3}" />
    </DataGrid.Columns>
</DataGrid>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM