gpt4 book ai didi

WPF GridSplitter - 保存和恢复位置并按比例拆分

转载 作者:行者123 更新时间:2023-12-04 01:07:44 26 4
gpt4 key购买 nike

我正在创建一个 3 列 UI,列之间有网格拆分器。我需要保存列的状态,这样如果用户关闭并重新打开应用程序,它看起来就像他们离开它一样。但我也试图让列按比例拆分——我的意思是,如果你拉伸(stretch)窗口,所有三个面板都会增长,如果你移动左拆分器,它会改变左列和中间列之间的划分。

我目前只实现了第一个要求 - 它保存了列宽的状态。我还让列强制所有三列的最小宽度。但据我了解,告诉拆分器按比例拆分的方法是使用星号大小的列宽。因为我已经在使用 Width 属性来保存和恢复状态,所以我不确定我能否完成我想要的。

有没有人设法保存列宽的状态并让拆分成比例?

这是我目前所拥有的一些代码:

   <Grid x:Name="mainGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="leftColumn" Width="{Binding MainWindowLeftColumnWidth, Mode=TwoWay, Source={x:Static prop:Settings.Default}}" MinWidth="200" MaxWidth="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}, Path=LeftColumnMaxWidth, Mode=OneWay}"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition x:Name="centerColumn" Width="{Binding MainWindowCenterColumnWidth, Mode=TwoWay, Source={x:Static prop:Settings.Default}}" MinWidth="300" MaxWidth="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}, Path=CenterColumnMaxWidth, Mode=OneWay}"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition x:Name="rightColumn" Width="*" MinWidth="500"/>
</Grid.ColumnDefinitions>
<StackPanel x:Name="leftPanel" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0"/>
<GridSplitter x:Name="leftSplitter" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" Width="5" ResizeDirection="Columns"/>
<StackPanel x:Name="centerPanel" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0"/>
<GridSplitter x:Name="rightSplitter" Grid.Column="3" HorizontalAlignment="Center" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" Width="5" ResizeDirection="Columns"/>
<StackPanel x:Name="rightPanel" Grid.Column="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0" SizeChanged="rightPanel_SizeChanged"/>
</Grid>

对于 LeftColumnMaxWidth 和 CenterColumnMaxWidth,我都有 double 类型的依赖属性。并且 rightPanel_SizeChanged 处理程序以及窗口加载处理程序都调用此方法:
    private void CalculateMaxWidths()
{
FrameworkElement content = Content as FrameworkElement;
if (content != null)
{
LeftColumnMaxWidth = content.ActualWidth
- leftSplitter.ActualWidth
- centerColumn.ActualWidth
- rightSplitter.ActualWidth
- rightColumn.MinWidth;
CenterColumnMaxWidth = content.ActualWidth
- leftColumn.ActualWidth
- leftSplitter.ActualWidth
- rightSplitter.ActualWidth
- rightColumn.MinWidth;
}
}

我还有一些工作要做,以确保调整窗口大小不会剪裁正确的列。我认为该解决方案可能与尝试使拆分器按比例拆分有关。我当前设置的特别特殊的行为是左拆分器调整左右列的大小,并保持中心列的大小固定。

我不怕处理 SizeChanged 或 DragDelta 来实现我的目标。但我认为我不能做的实际上是设置前两列的 Width 属性,因为这会破坏我与保存状态的用户设置的绑定(bind)。

预先感谢您的任何帮助。

最佳答案

所以我相信我已经想通了。我的 settings.settings 中的一些旧值可能会导致我出现问题,并且我输入的默认值可能会导致我出现问题。但这就是我所做的:

  • 更改了我的用户设置以保存所有三个(不仅仅是左两个)列宽。并将它们保存为字符串。
  • 将用户设置中的默认值(以及列上的宽度属性)设置为 200* 之类的值。
  • 在所有三列上仅设置 MinWidth - 而不是最大值。
  • 使用 GridLengthConverter 手动加载和保存列的用户设置。

  • 我不是 100% 相信这是最好的方法,但它似乎确实有效,这让我很高兴。万一其他人遇到问题并看到这篇文章,这里是有效的 XAML:
        <Grid x:Name="mainGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <Grid.ColumnDefinitions>
    <ColumnDefinition x:Name="leftColumn" MinWidth="200" Width="200*"/>
    <ColumnDefinition Width="Auto"/>
    <ColumnDefinition x:Name="centerColumn" MinWidth="300" Width="300*"/>
    <ColumnDefinition Width="Auto"/>
    <ColumnDefinition x:Name="rightColumn" MinWidth="498" Width="498*"/>
    </Grid.ColumnDefinitions>
    <StackPanel x:Name="leftPanel" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0"/>
    <GridSplitter x:Name="leftSplitter" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" Width="5" ResizeDirection="Columns"/>
    <StackPanel x:Name="centerPanel" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0"/>
    <GridSplitter x:Name="rightSplitter" Grid.Column="3" HorizontalAlignment="Center" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" Width="5" ResizeDirection="Columns"/>
    <StackPanel x:Name="rightPanel" Grid.Column="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0" SizeChanged="rightPanel_SizeChanged"/>
    </Grid>

    该大小更改事件仍然仅用于调试跟踪。我输出 Width 的值以查看发生了什么。奇怪的是,在展开所有内容并返回到窗口的最小尺寸后,右侧的列宽仍然更大。但是由于它们都有最小宽度并且宽度都是星型的,所以它会自行解决。

    我确实尝试将它放回绑定(bind)中,但由于我现在存储一个字符串,并且 GridLengthConverter 是 TypeConverter,而不是 IValueConverter,所以它不起作用。我认为可以将值存储为 GridLengths,尽管我已经达到了对我所做的事情感到满意的地步。所以我的加载和保存是这样的:
        protected override void OnSourceInitialized(EventArgs e)
    {
    base.OnSourceInitialized(e);

    //...

    try
    {
    GridLengthConverter converter = new GridLengthConverter();
    leftColumn.Width = (GridLength)converter.ConvertFromString(Settings.Default.MainWindowLeftColumnWidth);
    centerColumn.Width = (GridLength)converter.ConvertFromString(Settings.Default.MainWindowCenterColumnWidth);
    rightColumn.Width = (GridLength)converter.ConvertFromString(Settings.Default.MainWindowRightColumnWidth);

    Trace.WriteLine(string.Format("LOADED Left: {0}, Center: {1}, Right {2}", leftColumn.Width, centerColumn.Width, rightColumn.Width));
    }
    catch (Exception)
    {
    // Fail silently, the worse case is we go with the defaults, it's going to be okay
    }
    }

    protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
    {
    base.OnClosing(e);

    //...

    try
    {
    GridLengthConverter converter = new GridLengthConverter();
    Settings.Default.MainWindowLeftColumnWidth = converter.ConvertToString(leftColumn.Width);
    Settings.Default.MainWindowCenterColumnWidth = converter.ConvertToString(centerColumn.Width);
    Settings.Default.MainWindowRightColumnWidth = converter.ConvertToString(rightColumn.Width);

    Trace.WriteLine(string.Format("SAVED Left: {0}, Center: {1}, Right {2}", Settings.Default.MainWindowLeftColumnWidth, Settings.Default.MainWindowCenterColumnWidth, Settings.Default.MainWindowRightColumnWidth));
    }
    catch (Exception)
    {
    // Fail silently, the worst case is we don't save a little something, it's going to be okay
    }
    }

    这一切都对我有用。所以我要和它一起去!

    编辑:我后来做了一些改进,以防止右栏的“好奇心”保持更大。我现在将所有面板大小更改都转到一个事件处理程序:
        private void PanelSizeChanged(object sender, SizeChangedEventArgs e)
    {
    // In order to keep the resizing from losing proportionality, we'll force it to be proportional to the current size.
    // Otherwise the right panel edges up and up while the other two remain at their starting 200*/300* values.
    // And when that happens eventually resizing the window only resizes the right panel, not proportionately as it does at the start.
    leftColumn.Width = new GridLength(leftColumn.ActualWidth, GridUnitType.Star);
    centerColumn.Width = new GridLength(centerColumn.ActualWidth, GridUnitType.Star);
    rightColumn.Width = new GridLength(rightColumn.ActualWidth, GridUnitType.Star);
    }

    关于WPF GridSplitter - 保存和恢复位置并按比例拆分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5018544/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com