Question

I've got a StackPanel, and it's perfect for laying out columns that the user adds at runtime. But I'd like the columns to be resizable, and I was reading about the GridSplitter control. Here's what I'm wondering: Is the GridSplitter the wpf replacement for the WinForms splitter? In other words, is this the de facto way to allow the users to resize regions of the window? Does it only work inside of a Grid? If I have items inside a stackpanel or a dockpanel, can I still use a gridsplitter the way I used the splitter in WinForms? If I have to use a Grid, how can I make it behave just like a StackPanel? (hope it doesn't come to that)

Was it helpful?

Solution

Below is a user control which allows items to be added as columns. Between columns are grid splitters. Users can click on Delete button to remove added columns and columns can be added using behind code. Let me know if that's what you were looking for.

User control SmartGrid XAML:

<UserControl x:Class="SmartGridDemo.SmartGrid"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid Name="_grid">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
    </Grid>
</UserControl>  

User control SmartGrid code behind:

using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace SmartGridDemo
{
    public partial class SmartGrid : UserControl
    {
        public SmartGrid()
        {
            InitializeComponent();
        }

        public void Add(UIElement child)
        {
            int columnIndex = _grid.ColumnDefinitions.Count();

            _grid.ColumnDefinitions.Add(
                new ColumnDefinition() 
                {
                    Width = new GridLength(columnIndex == 0 ? 0 :5)
                });

            GridSplitter gridSplitter =
                new GridSplitter()
                {
                    HorizontalAlignment = HorizontalAlignment.Stretch,
                    VerticalAlignment = VerticalAlignment.Stretch,
                    ResizeDirection = GridResizeDirection.Columns,
                    Background = Brushes.Black
                };

            _grid.Children.Add(gridSplitter);
            Grid.SetColumn(gridSplitter, columnIndex);
            Grid.SetRow(gridSplitter, 0);
            Grid.SetRowSpan(gridSplitter, 2);

            columnIndex++;

            _grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });

            Button button = new Button();
            button.Content = "Delete";
            button.Tag = new TagTuple() {Child = child, GridSplitter = gridSplitter};
            button.Click += new RoutedEventHandler(DeleteButton_Click);

            _grid.Children.Add(button);
            Grid.SetColumn(button, columnIndex);
            Grid.SetRow(button, 0);

            _grid.Children.Add(child);
            Grid.SetColumn(child, columnIndex);
            Grid.SetRow(child, 1);
        }

        private void DeleteButton_Click(object sender, RoutedEventArgs e)
        {
            Button button = sender as Button;
            int columnIndex = Grid.GetColumn(button);
            TagTuple tagTuple = button.Tag as TagTuple;
            _grid.Children.Remove(tagTuple.GridSplitter);
            _grid.Children.Remove(tagTuple.Child);
            _grid.Children.Remove(button as UIElement);

            _grid.ColumnDefinitions.RemoveAt(_grid.ColumnDefinitions.Count() - 1);
            _grid.ColumnDefinitions.RemoveAt(_grid.ColumnDefinitions.Count() - 1);

            foreach (UIElement child in _grid.Children)
            { 
                int columnIndexForChild = Grid.GetColumn(child);
                if (columnIndexForChild > columnIndex)
                {
                    Grid.SetColumn(child, columnIndexForChild - 2);
                }
            }
        }

        private class TagTuple
        {
            public GridSplitter GridSplitter { get; set; }
            public UIElement Child { get; set; }
        }
    }
}

Demo code, add some text in the TextBox and hit Add button to add new columns, XAML:

<Window x:Class="SmartGridDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SmartGridDemo"    
    Title="SmartGridDemo" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <TextBox Name="_texBox" Grid.Row="0" Grid.Column="0" />
        <Button Content="Add" Click="AddButton_Click" Grid.Row="0" Grid.Column="1" />
        <local:SmartGrid x:Name="_smartGrid" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" />
    </Grid>
</Window>

Demo, behind code:

using System;
using System.Windows;
using System.Windows.Controls;

namespace SmartGridDemo
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            _smartGrid.Add(new TextBlock() { Text = "AAA" });
            _smartGrid.Add(new TextBlock() { Text = "BBB" });
            _smartGrid.Add(new TextBlock() { Text = "CCC" });
            _smartGrid.Add(new TextBlock() { Text = "DDD" });
            _smartGrid.Add(new TextBlock() { Text = "EEE" });
            _smartGrid.Add(new TextBlock() { Text = "FFF" });
        }

        private void AddButton_Click(object sender, RoutedEventArgs e)
        {
            _smartGrid.Add(new TextBlock() { Text = _texBox.Text });
        }
    }
}

OTHER TIPS

GridSplitter only works in a Grid and is the easiest way to allow users to resize controls. What do you mean that you want your grid (with gridsplitters) to behave just like a stackpanel? A stackpanel will exactly fit each of its children while a grid with gridsplitters will leave it up to the user.

Here is an open source WPF SplitContainer: [http://wpfsplitcontainer.codeplex.com/]

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top