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

时间:2014-06-12 23:00:16

标签: 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>

1 个答案:

答案 0 :(得分:0)

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

对于Rows,只需将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));
    }
}

需要注意的一点是 - 我的viewmodel的Width属性无法初始化为GridLength.Auto - 否则所有列都不会排列。