WPF UserControl 将 GridSplitter 附加到用户创建的 DataTemplate

标签 wpf grid gridsplitter

我有一个 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/

相关文章:

wpf - 初始焦点和全选行为

wpf - WPF 中 ListBoxItem 上的虚线边框

search - 网格存储配置抛出 "Uncaught TypeError: Cannot read property ' 缓冲'未定义"

c# - GridSplitter 禁用我的 RowDefinition 样式

c# - Grid Splitter 在对角线上工作?

wpf - 使用 Caliburn.Micro 的 WPF 应用程序中的全局处理异常

c# - 在 DataGrid 中设置焦点

delphi - TcxGrid自动发布是否关注另一行?

c# - 使用 GridSplitter 调整网格大小

c# - 如何以编程方式调整 PropertyGrid 控件的水平分隔线?