我有一個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