我正在创建一个3列UI,列之间有网格分割器。我需要保存列的状态,以便在用户关闭并重新打开应用程序时,它看起来就像是他们离开了它。但我也试图让柱子按比例分割 - 我的意思是,如果你拉伸窗口,所有三个面板都会增长,如果你移动左边的分割器,它会改变左边和中间列之间的分割。
我目前只实现了第一个要求 - 它保存了列宽的状态。我还使列强制所有三列的最小宽度。但据我了解,告诉拆分器按比例分割的方法是使用星形大小的列宽。由于我已经使用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处理程序以及Loaded处理程序窗口都调用此方法:
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属性,因为这会破坏我对保存状态的用户设置的绑定。
提前感谢您的帮助。
答案 0 :(得分:8)
所以我相信我已经弄明白了。我的settings.settings中的某些旧值可能会导致我出现问题,而且我输入的默认值可能会导致问题。但这就是我所做的:
我不是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);
}