100 votes

.NET WPF Mémoriser la taille de la fenêtre entre les sessions

En fait, lorsque l'utilisateur redimensionne la fenêtre de mon application, je veux que l'application ait la même taille lorsqu'elle est rouverte.

J'ai d'abord pensé à gérer l'événement SizeChanged et à enregistrer la hauteur et la largeur, mais je pense qu'il doit y avoir une solution plus simple.

Un problème assez simple, mais je ne trouve pas de solution facile.

2 votes

Veuillez noter que si vous réorganisez à la fois la taille et l'âge de l'enfant, vous devez vous assurer que l'enfant est en bonne santé. position (comme le font la plupart des exemples de code ci-dessous), vous voudrez gérer le cas limite où quelqu'un a débranché le moniteur sur lequel la fenêtre a été présentée en dernier lieu, afin d'éviter de présenter votre fenêtre hors écran.

0 votes

@OmerRaviv Avez-vous trouvé un exemple prenant en compte le cas limite ?

0 votes

J'ai trop peu de temps pour ajouter un commentaire, c'est pourquoi j'ai créé cette nouvelle alerte. J'utilise la même solution que Lance Cleveland y compris l'établissement de RobJohnson mais cela ne fonctionne pas si vous l'utilisez pour des sous-fenêtres et que vous voulez en ouvrir plusieurs en même temps...

126voto

ChrisF Points 74295

Enregistrez les valeurs dans le fichier user.config.

Vous devrez créer la valeur dans le fichier de configuration - il doit se trouver dans le dossier Propriétés. Créez cinq valeurs :

  • Top de type double
  • Left de type double
  • Height de type double
  • Width de type double
  • Maximized de type bool - pour tenir compte du fait que la fenêtre est maximisée ou non. Si vous voulez stocker plus d'informations, un autre type ou une autre structure sera nécessaire.

Initialiser les deux premiers à 0 et les deux seconds à la taille par défaut de votre application, et le dernier à false.

Créez un gestionnaire d'événement Window_OnSourceInitialized et ajoutez ce qui suit :

this.Top = Properties.Settings.Default.Top;
this.Left = Properties.Settings.Default.Left;
this.Height = Properties.Settings.Default.Height;
this.Width = Properties.Settings.Default.Width;
// Very quick and dirty - but it does the job
if (Properties.Settings.Default.Maximized)
{
    WindowState = WindowState.Maximized;
}

NOTE : Le placement de la fenêtre doit se faire dans l'événement initialisé à la source de la fenêtre et non dans le constructeur, sinon si la fenêtre est maximisée sur un deuxième moniteur, elle redémarrera toujours maximisée sur le moniteur principal et vous ne pourrez pas y accéder.

Créez un gestionnaire d'événement Window_Closing et ajoutez ce qui suit :

if (WindowState == WindowState.Maximized)
{
    // Use the RestoreBounds as the current values will be 0, 0 and the size of the screen
    Properties.Settings.Default.Top = RestoreBounds.Top;
    Properties.Settings.Default.Left = RestoreBounds.Left;
    Properties.Settings.Default.Height = RestoreBounds.Height;
    Properties.Settings.Default.Width = RestoreBounds.Width;
    Properties.Settings.Default.Maximized = true;
}
else
{
    Properties.Settings.Default.Top = this.Top;
    Properties.Settings.Default.Left = this.Left;
    Properties.Settings.Default.Height = this.Height;
    Properties.Settings.Default.Width = this.Width;
    Properties.Settings.Default.Maximized = false;
}

Properties.Settings.Default.Save();

Cette opération échouera si l'utilisateur réduit la zone d'affichage - soit en déconnectant un écran, soit en modifiant la résolution de l'écran - alors que l'application est fermée. Vous devez donc ajouter une vérification que l'emplacement et la taille souhaités sont toujours valides avant d'appliquer les valeurs.

0 votes

Que se passe-t-il si l'application est installée sous Program Files et que l'utilisateur s'exécute en tant que non-administrateur ?

0 votes

Désolé - je voulais dire user.config qui est stocké sous C:\Documents et Paramètres [utilisateur] \Local Paramètres \Application Données pour lesquelles l'[utilisateur] doit avoir des droits d'accès. Je vais mettre à jour la réponse.

5 votes

En fait, les paramètres ayant pour portée "User" ne sont pas enregistrés dans le fichier app.config dans Program Files, mais dans un fichier user.config dans le répertoire de données de l'application de l'utilisateur. Ce n'est donc pas un problème...

79voto

Thomas Levesque Points 141081

En fait, vous n'avez pas besoin d'utiliser le code-behind pour le faire (sauf pour enregistrer les paramètres). Vous pouvez utiliser une extension de balisage personnalisée pour lier la taille et la position de la fenêtre aux paramètres, comme ceci :

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:WpfApplication1"
        Title="Window1"
        Height="{my:SettingBinding Height}"
        Width="{my:SettingBinding Width}"
        Left="{my:SettingBinding Left}"
        Top="{my:SettingBinding Top}">

Vous pouvez trouver le code de cette extension de balisage ici : http://www.thomaslevesque.com/2008/11/18/wpf-binding-to-application-settings-using-a-markup-extension/

4 votes

J'aime cette réponse plus que la réponse acceptée choisie. Bien joué.

6 votes

+1 - J'adore l'utilisation de la reliure et des extensions ! Si vous ajoutez le WindowState à vos paramètres liés, il fournit toutes les capacités. Alternativement, si vous avez les paramètres de l'utilisateur disponibles dans le DataContext, vous pouvez utiliser quelque chose comme {Binding Settings.Height} etc.

0 votes

Cette approche pose un problème lorsque l'utilisateur ferme l'application alors que la fenêtre est agrandie.

43voto

RandomEngy Points 6937

Je viens d'écrire un article de blog détaillant comment faire cela d'une manière simple et robuste. Il utilise les fonctions GetWindowPlacement et SetWindowPlacement mentionnées par Andy, mais en supprimant certains des comportements étranges qu'il a mentionnés :

http://blogs.msdn.com/davidrickard/archive/2010/03/09/saving-window-size-and-location-in-wpf-and-winforms.aspx

36voto

Andy Points 15910

Bien que vous puissiez "vous débrouiller" et enregistrer manuellement les paramètres quelque part, et qu'en général cela fonctionne, il est très facile de ne pas traiter tous les cas correctement. Il est préférable de laisser le système d'exploitation faire le travail pour vous, en appelant GetWindowPlacement() à la sortie et SetWindowPlacement() au démarrage. Il gère tous les cas extrêmes qui peuvent se produire (moniteurs multiples, sauvegarde de la taille normale de la fenêtre si elle est fermée alors qu'elle est maximisée, etc.) afin que vous n'ayez pas à le faire.

Cet échantillon MSDN montre comment les utiliser avec une application WPF. L'exemple n'est pas parfait (la fenêtre commencera dans le coin supérieur gauche aussi petit que possible lors de la première exécution, et il y a un comportement étrange avec le concepteur de paramètres qui enregistre une valeur de type WINDOWPLACEMENT ), mais cela devrait au moins vous permettre de commencer.

0 votes

Bonne solution. Cependant, je viens de découvrir que les fonctions GetWindowPlacement/SetWindowPlacement sont non conscient d'Aero Snap

1 votes

@RandomEngy a posté une réponse améliorée basée sur ceci.

30voto

La liaison "longue" que Thomas a postée ci-dessus ne nécessite pratiquement aucun codage. Assurez-vous simplement que vous disposez de la liaison d'espace de nom :

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:p="clr-namespace:WpfApplication1.Properties"
        Title="Window1"
        Height="{Binding Source={x:Static p:Settings.Default}, Path=Height, Mode=TwoWay}"
        Width="{Binding Source={x:Static p:Settings.Default}, Path=Width, Mode=TwoWay}"
        Left="{Binding Source={x:Static p:Settings.Default}, Path=Left, Mode=TwoWay}"
        Top="{Binding Source={x:Static p:Settings.Default}, Path=Top, Mode=TwoWay}">

Ensuite, pour économiser sur le code-behind :

private void frmMain_Closed(object sender, EventArgs e)
{
    Properties.Settings.Default.Save();
}

0 votes

J'ai choisi cette solution, mais je n'ai sauvegardé les paramètres que si l'état de la fenêtre était normal, sinon il peut être difficile de la faire sortir du mode maximisé.

7 votes

+1 J'ai utilisé cela aussi, @DavidSykes - Ajouter un autre paramètre pour l'état de la fenêtre semble fonctionner assez bien, e.g. WindowState="{Binding Source={x:Static properties:Settings.Default}, Path=WindowState, Mode=TwoWay}"

0 votes

@RobJohnson J'ai essayé votre suggestion et cela a très bien fonctionné, merci.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X