我有一个 UserControl,它在网格上排列模板化项目(基于 this 问题的答案)。现在我想调整该网格的列/行的大小。
现在,我有一些技巧可以检测鼠标事件并计算用户是否在边界附近单击。如果是这样,它会调整适当的列。这大部分有效,但我遇到了相对较慢的 MouseMove 事件触发问题,导致用户很难单击正确的位置。另外,我无法扩大最后一行/列的大小,因为鼠标现在移动到控制区域之外,我无法跟踪它(尽管我可能可以通过更多工作来解决此问题)。
更好的解决方案是将 GridSplitters 添加到每列/行。问题是,我的 UserControl 使用 ItemsControl 和 DataTemplate 来创建项目,因此我在弄清楚如何添加拆分器时遇到了麻烦。我可以修改用户定义的模板吗?还有其他方法可以添加分离器吗?
* 编辑*
这是我想要做的一个示例(如果网格单元是手动定义的,而不是通过 ItemsControl 定义的)。请注意,此示例仍然没有解决调整最后一行大小的问题。
<Grid
Grid.Row="2" Grid.Column="1"
>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Text="Row 0" Grid.Row="0"/>
<GridSplitter
Grid.Row="0"
Height="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Background="Transparent"/>
<TextBox Text="Row 1" Grid.Row="1"/>
<GridSplitter
Grid.Row="1"
Height="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Background="Transparent"/>
<TextBox Text="Row 2" Grid.Row="2"/>
<GridSplitter
Grid.Row="2"
Height="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Background="Transparent"/>
</Grid>
最佳答案
可以通过将列的宽度绑定(bind)到 View 模型上的属性来完成列。这样,当 GridSplitter 移动时,它将更新该属性,进而更新其他项目。
对于行,只需将 GridSplitter 添加到 DataTemplate 的底部即可满足您的需求。
我创建了一个小小的 hacky 示例应用程序来说明:
我的窗口:
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
DataContext = new Context();
ItemsControl.ItemsSource = new ObservableCollection<Foo>
{
new Foo("Hello", "World1"),
new Foo("Hello1", "World2"),
new Foo("Hello2", "World3")
};
}
}
在 Xaml 中:
<ItemsControl Name="ItemsControl" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type utility:Foo}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Path=DataContext.Width, RelativeSource={RelativeSource FindAncestor, AncestorType=utility:MainWindow}, Mode=TwoWay}" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="5" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Path=Name}" Grid.Column="0" Grid.Row="0" Margin="5"/>
<GridSplitter Grid.Column="1" Grid.Row="0" Width="5" Height="Auto" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" ResizeDirection="Columns" />
<TextBlock Text="{Binding Path=Title}" Grid.Column="2" Grid.Row="0" Margin="5"/>
<GridSplitter Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="1" Height="5" Width="Auto" HorizontalAlignment="Stretch" ResizeBehavior="PreviousAndCurrent" ResizeDirection="Rows" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
使用以下数据上下文和项目:
public class Foo
{
public Foo(string name, string title)
{
Name = name;
Title = title;
}
public string Name { get; set; }
public string Title { get; set; }
}
public class Context : INotifyPropertyChanged
{
private GridLength _width = new GridLength(60);
public GridLength Width
{
get { return _width; }
set
{
if (_width == value) return;
_width = value;
RaisePropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
需要注意的重要一点 - 我的 View 模型的 Width 属性无法初始化为 GridLength.Auto - 否则所有列都不会对齐。
关于WPF UserControl 将 GridSplitter 附加到用户创建的 DataTemplate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24195201/