【问题标题】:WPF UserControl attach GridSplitter to user created DataTemplateWPF UserControl 将 GridSplitter 附加到用户创建的 DataTemplate
【发布时间】:2014-08-03 09:58:53
【问题描述】:

我有一个在网格上排列模板项目的 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>

【问题讨论】:

  • 你能发布同样的 XAML 吗?如果也有示例图像,我们将不胜感激。
  • 不确定我是否完全了解您要查找的 XAML。我加了一个……这涵盖了吗?
  • 用户控件中是否定义了网格?您可以发布定义网格的控件的 XAML 吗?
  • 网格是动态定义的。最简单的参考代码是查看我帖子顶部链接中接受的答案。

标签: wpf grid gridsplitter


【解决方案1】:

可以通过将列的宽度绑定到视图模型上的属性来完成列。这样,当 GridSplitter 移动时,它会更新属性,进而更新其他项。

对于行,只需在 DataTemplate 底部添加一个 GridSplitter 即可满足您的需求。

我创建了一个小小的 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));
    }
}

需要注意的一点 - 我的视图模型的 Width 属性不能初始化为 GridLength.Auto - 否则你的所有列都不会对齐。

【讨论】:

  • 谢谢,但这对我不起作用。首先,您已经明确定义了数据模板,但我正在创建一个通用控件,其中正在使用的数据模板在其他地方定义。其次,它依赖于具有 Width 属性的 ItemsSource,而 Width 属性表示列宽,我不能依赖它,因为它是一个通用控件。此外,您正在为碰巧排列的每个项目创建完全独立的网格。这很脆弱,因为正如您所指出的,如果将宽度设置为自动,则不再排列。
  • @JimBobBennet 关于您的最后一点:您可以使用相同的SharedSizeGroup 来排列列
  • @Eirik 不,当拆分器移动时,它不会调整其他列的大小。我确实尝试了它作为第一个解决方案,但它没有用。
  • @JimBobBennett 你记得在ItemsControl 上设置Grid.IsSharedSizeScope="True" 吗?
  • @Eirik - 是的。如果您有一个工作示例,将有兴趣查看。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-17
  • 2020-07-22
  • 2010-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多