dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
21.98k stars 1.71k forks source link

Splitter/Split View (User Adjustable) #15341

Open STIGsolution opened 1 year ago

STIGsolution commented 1 year ago

Description

I would like to request the addition of a user-resizable splitter feature. Currently, I have Desktop views that have a grid layout on the left and a vertical stack of text fields on the right. Clicking a line in the grid displays information about the selected item on the right.

I'd like to have a splitter between the two that can be clicked and dragged right or left to adjust the width of the grid.

Public API Changes

This is a sample of where I would use the splitter:

 <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <!-- Toolbar -->
        <StackLayout Grid.Row="0" BackgroundColor="LightGray" Padding="10">
            <!-- Toolbar content -->
            <telerik:RadToolbar x:Name="toolbar">
                <telerik:NavigationButtonToolbarItem Text="Search">
                    <telerik:NavigationButtonToolbarItem.ImageSource>
                        <FontImageSource Glyph="{x:Static telerik:TelerikFont.IconSearch}"
                                 FontFamily="{x:Static telerik:TelerikFont.Name}"
                                 Size="16" />
                    </telerik:NavigationButtonToolbarItem.ImageSource>
                    <telerik:LabelToolbarItem Text="Search" />
                    <telerik:ToolbarItem>
                        <telerik:ToolbarItem.ControlTemplate>
                            <ControlTemplate>
                                <Entry Placeholder="Search" VerticalTextAlignment="Center"/>
                            </ControlTemplate>
                        </telerik:ToolbarItem.ControlTemplate>
                    </telerik:ToolbarItem>
                </telerik:NavigationButtonToolbarItem>
            </telerik:RadToolbar>
            <telerik:RadToolbarOptionsPanel x:Name="topPanel" />
        </StackLayout>

        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="2*" />
            </Grid.ColumnDefinitions>

            <telerik:RadDataGrid x:Name="dataGrid" ItemsSource="{Binding}" AutoGenerateColumns="False">
                <telerik:RadDataGrid.Columns>
                    <telerik:DataGridTextColumn PropertyName="Name" SizeMode="Fixed"/>
                    <telerik:DataGridNumericalColumn PropertyName="Value"/>
                    <telerik:DataGridBooleanColumn PropertyName="IsEnabled"/>
                    <telerik:DataGridDateColumn PropertyName="Date" CellContentFormat="{}{0:MM/dd/yyyy}"/>
                </telerik:RadDataGrid.Columns>
            </telerik:RadDataGrid>

        <!-- Splitter -->
        <BoxView x:Name="splitter" Grid.Column="1" WidthRequest="5" BackgroundColor="Gray"
             HorizontalOptions="Center" VerticalOptions="FillAndExpand"/>

        <!-- Container with expanders -->
            <StackLayout Grid.Column="2" BackgroundColor="LightGray" Padding="10">
                <telerik:RadExpander x:Name="expanderVulnInfo" HeaderText="Vuln Info">
                    <telerik:RadExpander.Content>
                        <Label Text="Content" />
                    </telerik:RadExpander.Content>
                </telerik:RadExpander>
                <telerik:RadExpander x:Name="expanderTitle" HeaderText="Title">
                    <telerik:RadExpander.Content>
                        <Label Text="Content" />
                    </telerik:RadExpander.Content>
                </telerik:RadExpander>
                <telerik:RadExpander x:Name="expanderDiscussion" HeaderText="Discussion">
                    <telerik:RadExpander.Content>
                        <Label Text="Content" />
                    </telerik:RadExpander.Content>
                </telerik:RadExpander>
                <telerik:RadExpander x:Name="expanderCheck" HeaderText="Check">
                    <telerik:RadExpander.Content>
                        <Label Text="Content" />
                    </telerik:RadExpander.Content>
                </telerik:RadExpander>
                <telerik:RadExpander x:Name="expanderFix" HeaderText="Fix">
                    <telerik:RadExpander.Content>
                        <Label Text="Content" />
                    </telerik:RadExpander.Content>
                </telerik:RadExpander>
                <telerik:RadExpander x:Name="expanderMitigation" HeaderText="Mitigation">
                    <telerik:RadExpander.Content>
                        <Label Text="Content" />
                    </telerik:RadExpander.Content>
                </telerik:RadExpander>
                <telerik:RadExpander x:Name="expanderClosure" HeaderText="Closure">
                    <telerik:RadExpander.Content>
                        <Label Text="Content" />
                    </telerik:RadExpander.Content>
                </telerik:RadExpander>
            </StackLayout>
        </Grid>
    </Grid>

Intended Use-Case

Users using this view want to be able to change the width of the grid/stack to display more information on one side or the other.

ghost commented 1 year ago

We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.

QusaiSabri commented 1 year ago

Yes please!

STIGsolution commented 9 months ago

.NET 8 updates make it possible now to create a splitter. Here's a ContentView I'm using in my application to accomplish vertical splitter functionality between two columns by resizing the left column.

Place the splitter in your grid between two columns:

xmlns:local="clr-namespace:yournamespace.Controls"

<local:SplitterControl Grid.Column="1" x:Name="splitter"/>

Create SplitterControl ContentView:

SplitterControl.xaml.cs

namespace YourNameSpace.Resources.Controls;

public partial class SplitterControl : ContentView
{

    public SplitterControl()
    {
        InitializeComponent();
        SetupGestureRecognizers();
    }

    private void SetupGestureRecognizers()
    {
        var dragGestureRecognizer = new DragGestureRecognizer();
        dragGestureRecognizer.DragStarting += OnDragStarting;
        splitter.GestureRecognizers.Add(dragGestureRecognizer);

        PropertyChanged += (s, e) =>
        {
            if (e.PropertyName == "Parent" && Parent is Grid parentGrid)
            {
                var dropGestureRecognizer = new DropGestureRecognizer();
                dropGestureRecognizer.DragOver += OnDragOver;
                parentGrid.GestureRecognizers.Add(dropGestureRecognizer);
            }
        };
    }

    private void OnDragStarting(object sender, DragStartingEventArgs e)
    {
        splitter.IsVisible = false;
    }

    private void OnDragOver(object sender, DragEventArgs e)
    {
        UpdateSplitterPosition(sender, e);
    }

    public void UpdateSplitterPosition(object sender, DragEventArgs e)
    {
        int columnIndex = Grid.GetColumn(this);
        columnIndex--;

        var newWidth = (int)e.GetPosition(null)!.Value.X;

        if (DeviceInfo.Platform == DevicePlatform.WinUI)
        {
            e.PlatformArgs.DragEventArgs.DragUIOverride!.IsCaptionVisible = false;
            e.PlatformArgs.DragEventArgs.DragUIOverride!.IsGlyphVisible = false;
        }

        splitter.IsVisible = true;

        var parentGrid = Parent as Grid;

        if (parentGrid != null && columnIndex < parentGrid.ColumnDefinitions.Count)
        {
            parentGrid.ColumnDefinitions[columnIndex].Width = new GridLength(newWidth);
        }
    }
}

SplitterControl.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="YourNamespace.Resources.Controls.SplitterControl">
    <BoxView x:Name="splitter"
             WidthRequest="5"
             Color="#757474"
             HorizontalOptions="Center"
             VerticalOptions="FillAndExpand">
        <BoxView.GestureRecognizers>
            <DragGestureRecognizer DragStarting="OnDragStarting" />
        </BoxView.GestureRecognizers>
    </BoxView>
</ContentView>
BrunoVersa commented 8 months ago

Not working for me, it only move a little bit then it stops