c# appsettings - Restauration de la taille / position de la fenêtre avec plusieurs moniteurs




3 Answers

Essayez ce code. Points d'interêts:

  • Vérifie si la fenêtre est (partiellement) visible sur la zone de travail d'un écran. Par exemple en le faisant glisser derrière la barre des tâches ou en le déplaçant complètement hors écran, la position par défaut de Windows est réinitialisée.
  • Enregistre les limites correctes même si le formulaire est réduit ou maximisé (erreur commune)
  • Enregistre correctement le WindowState. L'enregistrement de FormWindowState.Minimized est désactivé par conception.

Les limites et l'état sont stockés dans les applis avec le type correspondant, il n'est donc pas nécessaire d'effectuer une analyse de chaîne. Laissez le framework faire sa magie de sérialisation.

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();

        // this is the default
        this.WindowState = FormWindowState.Normal;
        this.StartPosition = FormStartPosition.WindowsDefaultBounds;

        // check if the saved bounds are nonzero and visible on any screen
        if (Settings.Default.WindowPosition != Rectangle.Empty &&
            IsVisibleOnAnyScreen(Settings.Default.WindowPosition))
        {
            // first set the bounds
            this.StartPosition = FormStartPosition.Manual;
            this.DesktopBounds = Settings.Default.WindowPosition;

            // afterwards set the window state to the saved value (which could be Maximized)
            this.WindowState = Settings.Default.WindowState;
        }
        else
        {
            // this resets the upper left corner of the window to windows standards
            this.StartPosition = FormStartPosition.WindowsDefaultLocation;

            // we can still apply the saved size
            this.Size = Settings.Default.WindowPosition.Size;
        }
    }

    private bool IsVisibleOnAnyScreen(Rectangle rect)
    {
        foreach (Screen screen in Screen.AllScreens)
        {
            if (screen.WorkingArea.IntersectsWith(rect))
            {
                return true;
            }
        }

        return false;
    }

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);

        // only save the WindowState if Normal or Maximized
        switch (this.WindowState)
        {
            case FormWindowState.Normal:
            case FormWindowState.Maximized:
                Settings.Default.WindowState = this.WindowState;
                break;

            default:
                Settings.Default.WindowState = FormWindowState.Normal;
                break;
        }

        // reset window state to normal to get the correct bounds
        // also make the form invisible to prevent distracting the user
        this.Visible = false;
        this.WindowState = FormWindowState.Normal;

        Settings.Default.WindowPosition = this.DesktopBounds;
        Settings.Default.Save();
    }
}

Le fichier de paramètres pour référence:

<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="ScreenTest" GeneratedClassName="Settings">
    <Profiles />
    <Settings>
        <Setting Name="WindowPosition" Type="System.Drawing.Rectangle" Scope="User">
            <Value Profile="(Default)">0, 0, 0, 0</Value>
        </Setting>
        <Setting Name="WindowState" Type="System.Windows.Forms.FormWindowState" Scope="User">
            <Value Profile="(Default)">Normal</Value>
        </Setting>
    </Settings>
</SettingsFile>
save multiple

Nombreuses publications sur la restauration d'une position et d'une taille WinForm.

Exemples:

Mais je n'ai pas encore trouvé de code pour le faire avec plusieurs moniteurs.

Autrement dit, si je ferme mon application .NET Winform avec la fenêtre sur le moniteur 2, je souhaite qu’elle enregistre la taille, l’emplacement et l’état des fenêtres dans les paramètres de l’application, afin de pouvoir les restaurer ultérieurement au redémarrage de l’application. Ce serait bien si, comme dans l'exemple de codeproject ci-dessus, il incluait des vérifications d'intégrité, comme si l'emplacement sauvegardé était généralement hors écran, il le "corrige". Ou si l'emplacement enregistré se trouve sur un moniteur qui n'est plus là (par exemple, mon ordinateur portable est désormais autonome sans mon second moniteur), il le déplace correctement sur le moniteur 1.

Des pensées?

Mon environnement: C #, .NET 3.5 ou inférieur, VS2008




La plupart des autres solutions reposent ici sur la détermination manuelle du positionnement actuel de chaque moniteur. Les cas extrêmes sont extrêmement difficiles à comprendre, et très peu d’applications permettent de résoudre le problème.

La fonction SetWindowPlacement dans Windows lui-même gère correctement tous les cas de bord - si la fenêtre est positionnée sur un écran visible, elle est ajustée en conséquence.

Le meilleur exemple que j'ai vu en C # est sur le blog de David Rickard. Non seulement il montre comment utiliser SetWindowPlacement, mais il montre également comment sérialiser le résultat entier. http://blogs.msdn.com/b/davidrickard/archive/2010/03/09/saving-window-size-and-location-in-wpf-and-winforms.aspx




Si vous avez plusieurs moniteurs, je pense que les dimensions de l'interface utilisateur de l'écran sont simplement plus grandes. Ainsi, l’approche normale «1 moniteur» consistant à stocker et à restaurer l’emplacement fonctionnera simplement. Je n'ai pas essayé ceci parce que je suis loin de mon deuxième moniteur mais cela ne devrait pas être difficile à tester. La façon dont vous avez posé la question semble être que vous ne l'avez pas testée.

Votre deuxième exigence signifiera que vous devrez vérifier les dimensions maximales de l'écran lors de la restauration de l'application, puis repositionner si nécessaire. Pour faire ce dernier bit, j'utilise ce code:

    private System.Drawing.Rectangle ConstrainToScreen(System.Drawing.Rectangle bounds)
    {
        Screen screen = Screen.FromRectangle(bounds);
        System.Drawing.Rectangle workingArea = screen.WorkingArea;
        int width = Math.Min(bounds.Width, workingArea.Width);
        int height = Math.Min(bounds.Height, workingArea.Height);
        // mmm....minimax            
        int left = Math.Min(workingArea.Right - width, Math.Max(bounds.Left, workingArea.Left));
        int top = Math.Min(workingArea.Bottom - height, Math.Max(bounds.Top, workingArea.Top));
        return new System.Drawing.Rectangle(left, top, width, height);
    }

J'appelle cette méthode lors de la restauration du formulaire. Je stocke la géométrie de l'écran dans le registre à proximité de la forme, puis lis la géométrie ouverte du formulaire. J'obtiens les limites, mais contraint ensuite les limites restaurées à l'écran actuel, en utilisant la méthode ci-dessus.

Enregistrer à proximité:

      // store the size of the form
      int w = 0, h = 0, left = 0, top = 0;
      if (this.Bounds.Width < this.MinimumSize.Width || this.Bounds.Height < this.MinimumSize.Height)
      {
          // The form is currently minimized.  
          // RestoreBounds is the size of the window prior to last minimize action.
          w = this.RestoreBounds.Width;
          h = this.RestoreBounds.Height;
          left = this.RestoreBounds.Location.X;
          top = this.RestoreBounds.Location.Y;
      }
      else
      {
          w = this.Bounds.Width;
          h = this.Bounds.Height;
          left = this.Location.X;
          top = this.Location.Y;
      }
      AppCuKey.SetValue(_rvn_Geometry,
        String.Format("{0},{1},{2},{3},{4}",
              left, top, w, h, (int)this.WindowState));

Restaurer sur le formulaire ouvert:

    // restore the geometry of the form
    string s = (string)AppCuKey.GetValue(_rvn_Geometry);
    if (!String.IsNullOrEmpty(s))
    {
        int[] p = Array.ConvertAll<string, int>(s.Split(','),
                         new Converter<string, int>((t) => { return Int32.Parse(t); }));
        if (p != null && p.Length == 5)
            this.Bounds = ConstrainToScreen(new System.Drawing.Rectangle(p[0], p[1], p[2], p[3]));
    }



Related

c# winforms multiple-monitors appsettings