我有一个System.Windows.Controls.DataGrid属性CanUserResizeColumns分配给True。现在我可以通过在2列标题之间使用鼠标左键单击来调整列的宽度。WPF DataGrid:调整列大小
但我也希望能够更改dataGrid的任何行中列的宽度,而不仅仅是在列标题中。可能吗?
我有一个System.Windows.Controls.DataGrid属性CanUserResizeColumns分配给True。现在我可以通过在2列标题之间使用鼠标左键单击来调整列的宽度。WPF DataGrid:调整列大小
但我也希望能够更改dataGrid的任何行中列的宽度,而不仅仅是在列标题中。可能吗?
在你的数据网格,你可以在你的代码中使用DataGridTemplate
列alogn与GridSplitter
实现这个..
<toolkit:DataGridTemplateColumn Header="Text" >
<toolkit:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Text}"/>
<GridSplitter Grid.Column="1" Width="3"
DragIncrement="1"
DragDelta="GridSplitter_DragDelta"
Tag="{Binding BindsDirectlyToSource=True,
RelativeSource={RelativeSource
AncestorType={x:Type toolkit:DataGridCell}}}"/>
</Grid>
</DataTemplate>
</toolkit:DataGridTemplateColumn.CellTemplate>
</toolkit:DataGridTemplateColumn>
那么后面...做...
private void GridSplitter_DragDelta(
object sender,
System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
var gridSplitter = sender as GridSplitter;
if (gridSplitter != null)
{
((DataGridCell) gridSplitter.Tag).Column.Width
= ((DataGridCell) gridSplitter.Tag).Column.ActualWidth +
e.HorizontalChange;
}
}
这单个单元级别的GridSplitter可以调整整个列的大小。
如果您正在使用MVVM那么上面的事件处理程序应该放在一个附加行为
+1从我 - 。它的工作原理良好的乐趣,我决定用你的代码中附加的行为和使用张贴解答。 – RichardOD
从WPF,以其优良的答案继,这里是如何与附加的行为得到相同的结果:
public static class SplitterOnGridCellBehaviour
{
public static readonly DependencyProperty ChangeGridCellSizeOnDragProperty =
DependencyProperty.RegisterAttached("ChangeGridCellSizeOnDrag", typeof (bool),
typeof (SplitterOnGridCellBehaviour),
new PropertyMetadata(false, OnChangeGridCellSizeOnDrag));
private static void OnChangeGridCellSizeOnDrag(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
GridSplitter splitter = dependencyObject as GridSplitter;
if(splitter == null)
{
throw new NotSupportedException("SplitterOnGridCellBehaviour can only be on a GridSplitter");
}
if((bool)args.NewValue)
{
splitter.DragDelta += SplitterOnDragDelta;
}
else
{
splitter.DragDelta -= SplitterOnDragDelta;
}
}
private static void SplitterOnDragDelta(object sender, DragDeltaEventArgs args)
{
GridSplitter splitter = (GridSplitter)sender;
var containerCell = splitter.FindParent<DataGridCell>();
containerCell.Column.Width = containerCell.Column.ActualWidth + args.HorizontalChange;
}
public static void SetChangeGridCellSizeOnDrag(UIElement element, bool value)
{
element.SetValue(ChangeGridCellSizeOnDragProperty, value);
}
public static bool GetChangeGridCellSizeOnDrag(UIElement element)
{
return (bool) element.GetValue(ChangeGridCellSizeOnDragProperty);
}
public static T FindParent<T>(this DependencyObject child)
where T : DependencyObject
{
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
if (parentObject == null) return null;
var parent = parentObject as T;
if (parent != null)
{
return parent;
}
return FindParent<T>(parentObject);
}
}
为了让所有网格分隔符在DataGrid中显示为一个,我将DataGridCell的BorderThickness调整为0,否则所有网格分隔符都显示为破折号(至少在Windows 8上)。
的XAML的窗口看起来是这样的:
<Window x:Class="DataGridWithSplitter.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataGridWithSplitter" Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="CellWithSplitterTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Column1}"/>
<GridSplitter Grid.Column="1" Width="3" Background="Black" local:SplitterOnGridCellBehaviour.ChangeGridCellSizeOnDrag="True" />
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<DataGrid ItemsSource="{Binding SampleData}" GridLinesVisibility="None" HeadersVisibility="None" AutoGenerateColumns="False">
<DataGrid.Resources>
<!-- Makes the GridSplitters Solid -->
<Style TargetType="DataGridCell">
<Setter Property="BorderThickness" Value="0" />
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn Header="First Column" CellTemplate="{StaticResource CellWithSplitterTemplate}" />
<DataGridTextColumn Header="Other column" Binding="{Binding Column2}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
它的其余部分是相当明显的作用,但对于完整性Windows的DataContext的设置为以下视图模型代码的实例:
public class SampleData
{
public string Column1 { get; set; }
public string Column2 { get; set; }
}
public class MainWindowViewModel
{
public IEnumerable<SampleData> SampleData
{
get
{
return new List<SampleData>()
{
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
new SampleData() {Column1 = "Hello", Column2 = "World"},
};
}
}
}
这是另一种解决方案,不会污染您的数据网格内容。在DataGrid顶部画一个Canvas,在Canvas内有一个可以左右拖动的Line。拖动时,它会更新所需的列宽。
XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DataGrid x:Name="grid" Grid.Row="0" /> <!-- This is your data grid -->
<Canvas Grid.Row="0"> <!-- Canvas layerd over data grid -->
<Line StrokeThickness="4" Stroke="Transparent" Cursor="SizeWE"
X1="{Binding Columns[0].ActualWidth, ElementName=grid}"
X2="{Binding X1, RelativeSource={RelativeSource Self}}"
Y2="{Binding ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Canvas}}}"
MouseLeftButtonDown="OnSplitLineMouseLeftButtonDown"
MouseLeftButtonUp="OnSplitLineMouseLeftButtonUp"
MouseMove="OnSplitLineMouseMove"/>
</Canvas>
</Grid>
C#代码隐藏:
#region SplitBarHandling
bool splitBarDragging = false;
double splitBarMouseLastX = 0;
private void OnSplitLineMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
e.Handled = true;
splitBarDragging = true;
splitBarMouseLastX = e.GetPosition(null).X;
((UIElement)sender).CaptureMouse();
}
private void OnSplitLineMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
e.Handled = true;
splitBarDragging = false;
((UIElement)sender).ReleaseMouseCapture();
}
private void OnSplitLineMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (splitBarDragging)
{
e.Handled = true;
double newX = e.GetPosition(null).X;
grid.Columns[0].Width = grid.Columns[0].ActualWidth + (newX - splitBarMouseLastX);
splitBarMouseLastX = newX;
}
}
#endregion
注意我选择了把线透明,以便最终用户不会真正看到它。这是因为我已经依靠数据网格来显示列之间的垂直网格线。 此外,您可以选择线条粗细,无论您认为哪种线条都易于使用,又不影响网格单元的布局。我选择了4,因为即使数据网格将垂直网格线渲染为1像素宽,它也可以轻松拾取。
示例代码来自我自定义的PropertyGrid代码库,它只有两列,因此是硬编码的列0.为了进一步概括,我将它变成一个附加行为,支持所需的列数,或者子类DataGrid本身。
相比以前的解决方案,这其中只是增加了几个WPF元素支持的行为,无论你有多少数据网格行有,所以它可能是更有效的和可扩展的大型数据集。
戴安娜,你真的应该接受答案,否则社区将不会有动力去帮助你。 – MichaelS
不是。这太神秘了。 。:( –
@AngelWPF,我想她的意思 - 我可以通过拖动留下了细胞\右边界(如列标题的行为)调整列宽 有趣的问题,还有就是在Excel中没有这样的行为以及。 – MichaelS