WPF GridSplitter - 保存和恢复的位置和比例拆分 [英] WPF GridSplitter - saving and restoring location AND splitting proportionately

查看:1056
本文介绍了WPF GridSplitter - 保存和恢复的位置和比例拆分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创造与列之间的电网分离器有3栏UI。我要救列的沙爹的要求,因此,如果用户关闭并重新打开它看起来就像他们离开它的应用程序。但我也试图让列按比例分成 - 我的意思是,如果你拉伸窗口,这三个小组长,如果你移动左分路它改变了左边和中间列之间的分工

I am creating a 3-column UI with grid splitters between the columns. I have the requirement to save the sate of the columns so that if the user closes and reopens the app it looks just like they left it. But I am also trying to get the columns to split proportionately - by which I mean if you stretch the window, all three panels grow and if you move the left splitter it changes the division between the left and center columns.

我目前有仅达到第一个要求 - 它保存列宽的状态。我也取得了列执行最小宽度为所有三列。但据我了解,顺便告诉分路器按比例拆分是使用星大小的列宽。由于我使用的Width属性已经保存和恢复状态,我不知道我能做到我想做的。

What I have currently achieves only the first requirement - it saves the state of the column widths. I have also made the columns enforce minimum widths for all three columns. But as I understand it, the way to tell a splitter to split proportionately is to use star-sized column widths. Since I am using the Width property already to save and restore the state, I'm not sure I can accomplish what I want to.

有没有人设法既可以节省列宽的状态,并已拆分成比例?

Has anyone managed to both save the state of column widths AND have the split be proportional?

下面是一些code什么,我已经得到了目前:

Here is some code for what I've got currently:

   <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的依赖属性。而rightPanel_SizeChanged处理程序以及窗口加载处理程序都调用此方法:

I have dependency properties of type double for both LeftColumnMaxWidth and CenterColumnMaxWidth. And the rightPanel_SizeChanged handler as well as the window Loaded handler both call this method:

    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;
          }
    }

我还有一些工作要做,以确保调整窗口大小不夹右侧立柱。我认为,解决方案可能与试图使分离器分割比例。我目前成立了特别奇特的行为是左分路器调整大小,左,右列,离开中心柱尺寸固定的。

I still have some work to do to make sure that resizing the window doesn't clip the right column. I think that solution may be related to trying to make the splitters split proportionately. The particularly peculiar behavior of my current set up is that the left splitter resizes the left and right columns, and leaves the center column size fixed.

我不怕处理时,SizeChanged或DragDelta来实现自己的目标。但我相信,我不能这样做实际上是设置在前两列的Width属性,因为这会破坏我的结合,节省了国家的用户设置。

I am not afraid of handling SizeChanged or DragDelta to achieve my goals. But what I believe I cannot do is actually set the Width property of the first two columns, as that would destroy my binding to the user setting that saves the state.

感谢您事先的任何帮助。

Thank you in advance for any help.

推荐答案

所以,我相信我已经想通了这一点。这可能是我在settings.settings一些旧值害我的问题,这可能是我把默认值,引起了我的问题。但这里是我所做的:

So I believe I have figured this out. It is possible that some old values in my settings.settings were causing me issues, and it's possible that the default values I put in caused me issues. But here's what I did:


  1. 改变我的用户设置保存所有三个(不只是左二)列宽。并将其保存为字符串。

  2. 在用户设置的默认(以及在列的宽度属性)设定为类似200 *

  3. 设置只有了minWidth - 而不是最大 - 在所有三列

  4. 手动加载并使用GridLengthConverter保存列的用户设置。

我不是100%相信这是最好的方式,但它似乎工作,这让我非常高兴。如果任何人有麻烦,遇到这个帖子,这里是工作的XAML:

I'm not 100% convinced this is the best way, but it does seem to work, which makes me quite happy. In case anyone else has trouble and comes across this post, here is the working 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>

这改变大小事件依然存在只为调试跟踪。 I输出宽度的值,看看发生了什么。奇怪的是,扩大一切,回到窗口的最小尺寸后,右边的列宽撑大。但是,因为它们都具有minwidths和宽度都是明星般大小,它的工作原理本身了。

That size changed event is still there only for debug tracing. I output the values of Width to see what is happening. Curiously, after expanding everything and going back to the window's minimum size, the right column width stays larger. But since they all have minwidths and the widths are all star-sized, it works itself out.

我曾尝试把这个回有约束力的,但因为我现在存储一个字符串,GridLengthConverter是的TypeConverter,不是的IValueConverter,它没有工作。我认为这是可能的值存储为GridLengths,虽然我已经到了一个地步,我很高兴我做了什么。所以,我的加载和保存都是这样的:

I did try to put this back into a binding, but since I'm now storing a string, and the GridLengthConverter is a TypeConverter, not an IValueConverter, it didn't work. I think it may be possible to store the values as GridLengths, though I've reached a point where I'm happy with what I've done. So my load and save are like this:

    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
        }
    }

和所有为我工作。所以我打算去用它!

And that all worked for me. So I'm going to go with it!

编辑:我后来做了一些改进,以prevent的右栏住更大的好奇心。我现在所有的面板尺寸的变化去一个事件处理程序:

I later did some refinement to prevent the "curiosity" of the right column staying larger. I now have all panel size changes go to one event handler:

    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 - 保存和恢复的位置和比例拆分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆