如何反转WPF网格布局中的列顺序?

问题描述 投票:0回答:1

我正在用 C# 构建一个 WPF 应用程序。 我正在尝试使用

Grid
布局实现两列布局,类似于浏览器侧边栏。

Grid
实现为 3 列布局,因为我使用
GridSplitter
来轻松更改侧边栏的宽度。

侧边栏是可以折叠的,所以参考下面的Style进行设置,这样使用后就可以毫无问题地折叠了

GridSplitter

WPF:折叠 GridSplitter?

默认情况下,侧边栏位于右侧,但我想在代码中动态颠倒顺序。

MainContent | GridSplitter | Sidebar
<---->
Sidebar | GridSplitter | MainContent

主窗口.xaml

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        d:DataContext="{d:DesignInstance local:MainWindow}">
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <!--Main Column-->
            <ColumnDefinition Width="*" />
            <!--GridSplitter -->
            <ColumnDefinition Width="Auto" />

            <!--Collapsable Sidebar Column -->
            <!--Can collapse entirely even if GridSplitter is used -->
            <!--ref: https://stackoverflow.com/questions/12483017/wpf-collapse-gridsplitter-->
            <ColumnDefinition>
                <ColumnDefinition.Style>
                    <Style TargetType="{x:Type ColumnDefinition}">
                        <Style.Setters>
                            <Setter Property="Width" Value="200"/>
                        </Style.Setters>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ShowSidebar}" Value="False">
                                <DataTrigger.Setters>
                                    <Setter Property="Width" Value="0"/>
                                    <Setter Property="MaxWidth" Value="0"/>
                                </DataTrigger.Setters>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ColumnDefinition.Style>
            </ColumnDefinition>
        </Grid.ColumnDefinitions>

        <!--Main Column-->
        <Grid Grid.Column="0" Background="White">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>

            <StackPanel Orientation="Horizontal">
                <Button Content="Toggle sidebar" Click="ToggleSidebarButton_OnClick" />
                <Button Content="Swap sidebar" Click="SwapSidebarButton_OnClick" />
            </StackPanel>

            <TextBlock
                Grid.Row="1"
                Text="Main Content"
                FontSize="32"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"/>
        </Grid>

        <GridSplitter
            Grid.Column="1"
            Visibility="{Binding ShowSidebar, Converter={StaticResource BooleanToVisibilityConverter}}"
            Width="5"
            ShowsPreview="True"
            ResizeBehavior="PreviousAndNext"
            ResizeDirection="Columns" />

        <!--Sidebar Column-->
        <Grid
            Grid.Column="2"
            Visibility="{Binding ShowSidebar, Converter={StaticResource BooleanToVisibilityConverter}}"
            Background="Gray">

            <TextBlock
                Text="Sidebar"
                FontSize="32"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"/>
        </Grid>
    </Grid>
</Window>

MainWindow.xaml.cs

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private bool _showSidebar = true;
        public bool ShowSidebar
        {
            get => _showSidebar;
            set => SetField(ref _showSidebar, value);
        }

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        private void ToggleSidebarButton_OnClick(object sender, RoutedEventArgs e)
        {
            ShowSidebar = !ShowSidebar;
        }

        private void SwapSidebarButton_OnClick(object sender, RoutedEventArgs e)
        {
            // TODO: How to swap the sidebar programmatically?
            throw new NotImplementedException();
        }

        #region IPC
        public event PropertyChangedEventHandler? PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected bool SetField<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(field, value)) return false;
            field = value;
            OnPropertyChanged(propertyName);
            return true;
        }
        #endregion

    }
}

TODO 部分是用代码隐藏编写的,但我实际上想使用 MVVM 在 ViewModel 中实现它。

我已经确认可以使用如下所示的 5 列布局来实现这一点,通过创建两个变量

ShowSidebarRight
ShowSidebarLeft
,分别放置两个 SidebarView 和 GridSplitter,并用
Visibility
控制显示来实现。

但我想只用一个 View 实例来实现它,因为它会创建一个额外的 SidebarView 和 ViewModel 实例,这会导致性能问题和代码冗余。

        <Grid.ColumnDefinitions>
            <!--Left Sidebar -->
            <ColumnDefinition>
                <ColumnDefinition.Style>
                    <Style TargetType="{x:Type ColumnDefinition}">
                        <Style.Setters>
                            <Setter Property="Width" Value="200"/>
                        </Style.Setters>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ShowSidebarLeft}" Value="False">
                                <DataTrigger.Setters>
                                    <Setter Property="Width" Value="0"/>
                                    <Setter Property="MaxWidth" Value="0"/>
                                </DataTrigger.Setters>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ColumnDefinition.Style>
            </ColumnDefinition>

            <!--Left GridSplitter -->
            <ColumnDefinition Width="Auto" />
            <!--Main Column-->
            <ColumnDefinition Width="*" />
            <!--Right GridSplitter -->
            <ColumnDefinition Width="Auto" />
            <!--Right Sidebar -->
            <ColumnDefinition>
                <ColumnDefinition.Style>
                    <Style TargetType="{x:Type ColumnDefinition}">
                        <Style.Setters>
                            <Setter Property="Width" Value="200"/>
                        </Style.Setters>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ShowSidebarRight}" Value="False">
                                <DataTrigger.Setters>
                                    <Setter Property="Width" Value="0"/>
                                    <Setter Property="MaxWidth" Value="0"/>
                                </DataTrigger.Setters>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ColumnDefinition.Style>
            </ColumnDefinition>
        </Grid.ColumnDefinitions>
c# wpf wpf-controls wpf-grid
1个回答
0
投票

您可以通过设置

FlowDirection
属性来反转水平布局顺序:

<Grid FlowDirection="RightToLeft">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="200"/>
    </Grid.ColumnDefinitions>

    <Grid Grid.Column="0" FlowDirection="LeftToRight">
        <TextBlock Text="Main Content"/>
    </Grid>

    <Grid Grid.Column="2" FlowDirection="LeftToRight">
        <TextBlock Text="Sidebar"/>
    </Grid>

    <GridSplitter
        Grid.Column="1"
        Width="5"
        ShowsPreview="True"
        ResizeBehavior="PreviousAndNext"
        ResizeDirection="Columns" />
</Grid>
© www.soinside.com 2019 - 2024. All rights reserved.