我试图将一个数据网格的标题宽度绑定到另一个数据网格的标题.
所以,我为父数据网格的每一行添加了一个数据网格.现在,我试图使用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)