2011-02-16 64 views
10

我正在用列間的網格分隔符創建3列UI。我有要求保存列的狀態,以便如果用戶關閉並重新打開應用程序,它看起來就像他們離開它。但我也試圖讓列按比例分割 - 我的意思是,如果您拉伸窗口,所有三個面板都會增長,如果您移動左側分割線,它將更改左側和中間列之間的分割。WPF GridSplitter - 保存和恢復位置並按比例分割

我目前只實現了第一個要求 - 它節省了列寬的狀態。我也使這些列強制所有三列的最小寬度。但據我瞭解,分配器按比例分配的方式是使用星號大小的列寬。由於我正在使用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的依賴屬性。而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屬性,因爲這會破壞我綁定到保存狀態的用戶設置。

非常感謝您的幫助。

回答

6

所以我相信我已經想通了。我的settings.settings中的一些舊值可能會導致我遇到問題,並且可能我放入的默認值導致了問題。但這是我做了什麼:

  1. 更改我的用戶設置以保存所有THREE(不只是左側兩列)的寬度。並將它們保存爲字符串。
  2. 將用戶設置中的默認值(以及列上的寬度屬性)設置爲200 *。
  3. 在所有三列上只設置MinWidth - 不是最大值。
  4. 使用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的值來看看發生了什麼。奇怪的是,在擴展所有內容並返回到窗口的最小尺寸後,右列寬度保持較大。但是由於它們都具有最小寬度並且寬度都是明星大小的,所以它自行解決。

我確實試圖把它放回到一個綁定中,但由於我現在正在存儲一個字符串,而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); 
    }