WPF GridSplitter - guardar e restaurar o local E dividir proporcionalmente
-
14-11-2019 - |
Pergunta
Estou criando um 3-coluna de INTERFACE do usuário com grade de divisores entre as colunas.Eu tenho a exigência para salvar o estado das colunas, de modo que se o usuário fecha e reabre o aplicativo olha só como eles deixaram.Mas eu também estou tentando obter as colunas para dividir proporcionalmente - por que eu quero dizer, se você esticar a janela, todos os três painéis de crescer e de se mover da esquerda divisor ele muda a divisão entre a esquerda e o centro de colunas.
O que eu tenho atualmente atinge apenas o primeiro requisito - guarda o estado das larguras de coluna.Eu também fiz as colunas mínimos larguras para todas as três colunas.Mas, como eu a entendo, a maneira de contar uma divisão para dividir proporcionalmente, é a estrela de tamanho larguras de coluna.Desde que eu estou usando a propriedade de Largura já para salvar e restaurar o estado, eu não tenho certeza se eu posso fazer o que eu quiser.
Alguém já conseguiu salvar o estado de larguras de coluna E de ter de dividir a ser proporcional?
Aqui está um código para o que eu tenho atualmente:
<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>
Eu tenho as propriedades de dependência do tipo double para tanto LeftColumnMaxWidth e CenterColumnMaxWidth.E o rightPanel_SizeChanged manipulador, bem como a janela Carregada manipulador de tanto chamar esse método:
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;
}
}
Eu ainda tenho algum trabalho a fazer para se certificar de que o redimensionamento da janela não se prenda a coluna da direita.Eu acho que a solução pode estar relacionado a tentar fazer os divisores dividido proporcionalmente.Particularmente o comportamento peculiar do meu set atual é que a esquerda divisor redimensiona as colunas esquerda e direita, e deixa o centro de coluna de tamanho fixo.
Eu não tenho medo de manuseio SizeChanged ou DragDelta para alcançar meus objetivos.Mas o que eu acredito que não pode fazer é, na verdade, defina a propriedade Largura das duas primeiras colunas, que iria destruir a minha ligação para a configuração de usuário que salva o estado.
Obrigado antecipadamente por qualquer ajuda.
Solução
Então eu acredito que eu já descobriu isso.É possível que alguns valores antigos no meu de configurações.as definições estavam me causando problemas, e é possível que os valores padrão eu coloco me causou problemas.Mas aqui está o que eu fiz:
- Mudou a minha definições de utilizador para guardar todos os TRÊS (e não apenas a esquerda duas) larguras de coluna.E salvá-los como seqüências de caracteres.
- Definir o padrão as configurações do usuário (assim como a propriedade de largura nas colunas) para algo como 200*.
- Defina apenas o MinWidth - não o max. - em todos os três colunas.
- Carregar manualmente e guardar as definições do utilizador para as colunas utilizando um GridLengthConverter.
Eu não estou 100% convencido de que este é o melhor caminho, mas ele não parece funcionar, o que me faz muito feliz.No caso de mais alguém tem problemas e vem através deste post, aqui está a trabalhar 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>
Que tamanho alterado evento ainda está lá apenas para o rastreamento de depuração.Eu de saída os valores de Largura para ver o que está acontecendo.Curiosamente, após uma expansão de tudo e voltar para a janela do tamanho mínimo, o direito de largura de coluna estadias maiores.Mas desde que todos eles têm minwidths e as larguras de todas as estrelas de tamanho, trabalha-se para fora.
Eu tentei colocar isso de volta em uma ligação, mas desde que eu sou agora armazenar uma cadeia de caracteres, e o GridLengthConverter é um TypeConverter, não o ivalueconverter, não funcionou.Eu acho que pode ser possível para armazenar os valores como GridLengths, embora eu tenha chegado a um ponto em que eu estou feliz com o que eu tenho feito.Então, a minha carregar e salvar são como este:
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
}
}
E que todos os funcionou para mim.Então, eu estou indo para ir com ele!
EDITAR:Mais tarde eu fiz algumas requinte para evitar a "curiosidade" da coluna da direita ficar maior.Agora tenho tudo o painel de alterações de tamanho de ir para um manipulador de eventos:
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);
}