.NET WPF Oturumlar arasındaki pencere boyutunu hatırla


94

Temel olarak, kullanıcı uygulamamın penceresini yeniden boyutlandırdığında, uygulama yeniden açıldığında uygulamanın aynı boyutta olmasını istiyorum.

İlk başta SizeChanged olayını işlemeyi ve Yükseklik ve Genişliği kaydetmeyi düşündüm, ancak daha kolay bir çözüm olması gerektiğini düşünüyorum.

Oldukça basit bir problem ama buna kolay bir çözüm bulamıyorum.


2
Lütfen hem boyutu hem de konumu (aşağıdaki kod örneklerinin çoğunun yaptığı gibi) resmileştiriyorsanız , birisinin pencerenin en son sunulduğu monitörü fişten çıkardığı uç durumu ele almak isteyeceğinizi unutmayın. pencere ekran dışı.
Ömer Raviv

@OmerRaviv Uç durumu hesaba katan bir örnek buldunuz mu?
Andrew Truckle

Yorum eklemek için çok az itibarım var, bu nedenle bu yeni tarayıcıyı yarattım. RobJohnson ayarı da dahil olmak üzere Lance Cleveland ile aynı çözümü kullanıyorum , ancak alt pencereler için kullanırsanız ve aynı anda daha fazlasını açmak istiyorsanız işe yaramaz ...
AelanY

Yanıtlar:


122

Değerleri user.config dosyasına kaydedin.

Değeri ayarlar dosyasında oluşturmanız gerekir - Özellikler klasöründe olmalıdır. Beş değer oluşturun:

  • Top tip double
  • Left tip double
  • Height tip double
  • Width tip double
  • Maximizedtür bool- pencerenin ekranı kaplayıp büyütülmediğini tutmak için. Daha fazla bilgi depolamak istiyorsanız, farklı bir tür veya yapı gerekli olacaktır.

İlk ikisini 0'a ve ikinci ikisini uygulamanızın varsayılan boyutuna ve sonuncusunu yanlış olarak başlatın.

Bir Window_OnSourceInitialized olay işleyicisi oluşturun ve aşağıdakileri ekleyin:

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;
}

NOT: Ayarlanan pencere yerleşiminin, kurucunun değil, pencerenin kaynakta başlatılan olayına gitmesi gerekir, aksi takdirde pencereyi ikinci bir monitörde büyütürseniz, birincil monitörde her zaman büyütülmüş olarak yeniden başlatılır ve bunu yapamazsınız. erişmek için.

Bir Window_Closing olay işleyicisi oluşturun ve aşağıdakileri ekleyin:

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();

Kullanıcı, uygulama kapalıyken ekran alanını küçültürse (bir ekranın bağlantısını keserek veya ekran çözünürlüğünü değiştirerek) başarısız olur, bu nedenle değerleri uygulamadan önce istenen konum ve boyutun hala geçerli olup olmadığını kontrol etmelisiniz.


5
Gerçekte, "Kullanıcı" kapsamına sahip ayarlar, Program Dosyaları'ndaki app.config dosyasına değil, kullanıcının uygulama verileri dizinindeki bir user.config dosyasına kaydedilir. Yani sorun değil ...
Thomas Levesque

7
Aslında ayarlara "WindowState" ekleyebilirsiniz. Tür seçin -> gözat -> PresentationFramework -> System.Windows -> WindowState :)
Martin Vseticka

2
FWIW, uygulama çökmesi durumunda bunu boyut değiştiriciden de yapıyorum. İşlenmemiş bir istisna işleme ile nadirdirler, ancak gizemli bir şekilde meydana geldiklerinde neden kullanıcıyı boyut / konum kaybı ile cezalandırın?
Thomas

7
Bu kodda, kullanıcı ikinci ekranında pencereyi açıp daha sonra bu ekranın bilgisayarla olan bağlantısını keserse, pencereyi bir sonraki açışında ekran dışında gösterilecek olmasıyla ilgili bir hata var. Pencere kalıcı ise, kullanıcı uygulamayla hiçbir şekilde etkileşim kuramaz ve neler olduğunu anlamaz. Ekran koordinatlarını DPI bağımlı değerlere dönüştürdükten
Ömer Raviv

2
@OmerRaviv - bu bir hata değil, sınırlama :) Cidden - sorunun bu yönüne değinmedim.
ChrisF

74

Aslında bunu yapmak için arka planda kod kullanmanıza gerek yoktur (ayarları kaydetmek dışında). Pencere boyutunu ve konumunu aşağıdaki gibi ayarlara bağlamak için özel bir biçimlendirme uzantısı kullanabilirsiniz:

<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}">

Bu işaretleme uzantısının kodunu burada bulabilirsiniz: http://www.thomaslevesque.com/2008/11/18/wpf-binding-to-application-settings-using-a-markup-extension/


4
Bu cevabı, seçilen kabul edilmiş cevaptan daha çok seviyorum. Aferin.
moswald

6
+1 - Bağlama ve uzantıların kullanımını seviyorum! WindowState'i bağlı ayarlarınıza eklerseniz, tüm yetenekleri sağlar. Alternatif olarak, DataContext'te kullanıcı ayarlarına sahipseniz, bunun gibi bir şey kullanabilirsiniz {Binding Settings.Height}.
Matt DeKrey

Bu yaklaşım, Pencere Ekranı Büyütüldüğünde kullanıcı uygulamayı kapattığında bir soruna sahiptir.
Vinicius Rocha

@Vinicius, detaylandırır mısın? Sorun tam olarak nedir?
Thomas Levesque

4
İnsanların iki monitörü olduğunda ve bu nedenle negatif koordinatlara sahip olduklarında ve ardından monitör yapılandırmalarını değiştirdiklerinde ve değerler artık geçerli olmadığında ne olur?
Andrew Truckle

33

"Kendi başınıza dönebilirsiniz" ve ayarları bir yere manuel olarak kaydedebilirsiniz ve genel olarak işe yarayacaktır, ancak tüm durumları doğru şekilde ele almamak çok kolaydır. Çıkışta GetWindowPlacement () ve başlangıçta SetWindowPlacement () çağırarak işletim sisteminin sizin için işi yapmasına izin vermek çok daha iyidir . Ortaya çıkabilecek tüm çılgın uç durumları (birden fazla monitör, büyütülmüş haldeyken kapalıysa pencerenin normal boyutunu kaydetme vb.) Yönetir, böylece gerek kalmaz.

Bu MSDN Örneği , bunların bir WPF uygulamasıyla nasıl kullanılacağını gösterir. Örnek mükemmel değil (pencere ilk çalıştırmada olabildiğince küçük sol üst köşede başlayacak ve Ayarlar tasarımcısının bir tür değeri kaydetmesiyle ilgili bazı garip davranışlar var WINDOWPLACEMENT), ancak en azından başlamanıza yardımcı olmalı.


Güzel çözüm. Ancak GetWindowPlacement / SetWindowPlacement'ın Aero Snap'in farkında olmadığını
Mark Bell

1
@RandomEngy, buna dayalı olarak geliştirilmiş bir cevap yayınladı.
Stéphane Gourichon

27

Thomas'ın yukarıda yayınladığı "uzun biçimli" bağlama neredeyse hiç kodlama gerektirmez, yalnızca ad alanı bağlantısına sahip olduğunuzdan emin olun:

<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}">

Ardından arka plan kodundan tasarruf etmek için:

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

Bu çözümü seçtim, ancak yalnızca pencere durumu normalse ayarları kaydettim, aksi takdirde onu maksimize edilmiş moddan zor bir şekilde çıkarabilir
David Sykes

7
+1 Bunu da kullandım @DavidSykes - Pencere durumu için başka bir ayar eklemek yeterince iyi çalışıyor gibi görünüyor, örneğinWindowState="{Binding Source={x:Static properties:Settings.Default}, Path=WindowState, Mode=TwoWay}"
RobJohnson

@RobJohnson Önerinizi denedim ve çok iyi çalıştı, teşekkürler.
David Sykes

4

Alternatif olarak, aşağıdaki yaklaşımı da beğenebilirsiniz ( kaynağa bakın ). WindowSettings sınıfını projenize ekleyin WindowSettings.Save="True"ve ana pencerenizin başlığına ekleyin :

<Window x:Class="YOURPROJECT.Views.ShellView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Services="clr-namespace:YOURNAMESPACE.Services" 
    Services:WindowSettings.Save="True">

WindowSettings aşağıdaki gibi tanımlanır:

using System;
using System.ComponentModel;
using System.Configuration;
using System.Windows;

namespace YOURNAMESPACE.Services
{
/// <summary>
///   Persists a Window's Size, Location and WindowState to UserScopeSettings
/// </summary>
public class WindowSettings
{
    #region Fields

    /// <summary>
    ///   Register the "Save" attached property and the "OnSaveInvalidated" callback
    /// </summary>
    public static readonly DependencyProperty SaveProperty = DependencyProperty.RegisterAttached("Save", typeof (bool), typeof (WindowSettings), new FrameworkPropertyMetadata(OnSaveInvalidated));

    private readonly Window mWindow;

    private WindowApplicationSettings mWindowApplicationSettings;

    #endregion Fields

    #region Constructors

    public WindowSettings(Window pWindow) { mWindow = pWindow; }

    #endregion Constructors

    #region Properties

    [Browsable(false)] public WindowApplicationSettings Settings {
        get {
            if (mWindowApplicationSettings == null) mWindowApplicationSettings = CreateWindowApplicationSettingsInstance();
            return mWindowApplicationSettings;
        }
    }

    #endregion Properties

    #region Methods

    public static void SetSave(DependencyObject pDependencyObject, bool pEnabled) { pDependencyObject.SetValue(SaveProperty, pEnabled); }

    protected virtual WindowApplicationSettings CreateWindowApplicationSettingsInstance() { return new WindowApplicationSettings(this); }

    /// <summary>
    ///   Load the Window Size Location and State from the settings object
    /// </summary>
    protected virtual void LoadWindowState() {
        Settings.Reload();
        if (Settings.Location != Rect.Empty) {
            mWindow.Left = Settings.Location.Left;
            mWindow.Top = Settings.Location.Top;
            mWindow.Width = Settings.Location.Width;
            mWindow.Height = Settings.Location.Height;
        }
        if (Settings.WindowState != WindowState.Maximized) mWindow.WindowState = Settings.WindowState;
    }

    /// <summary>
    ///   Save the Window Size, Location and State to the settings object
    /// </summary>
    protected virtual void SaveWindowState() {
        Settings.WindowState = mWindow.WindowState;
        Settings.Location = mWindow.RestoreBounds;
        Settings.Save();
    }

    /// <summary>
    ///   Called when Save is changed on an object.
    /// </summary>
    private static void OnSaveInvalidated(DependencyObject pDependencyObject, DependencyPropertyChangedEventArgs pDependencyPropertyChangedEventArgs) {
        var window = pDependencyObject as Window;
        if (window != null)
            if ((bool) pDependencyPropertyChangedEventArgs.NewValue) {
                var settings = new WindowSettings(window);
                settings.Attach();
            }
    }

    private void Attach() {
        if (mWindow != null) {
            mWindow.Closing += WindowClosing;
            mWindow.Initialized += WindowInitialized;
            mWindow.Loaded += WindowLoaded;
        }
    }

    private void WindowClosing(object pSender, CancelEventArgs pCancelEventArgs) { SaveWindowState(); }

    private void WindowInitialized(object pSender, EventArgs pEventArgs) { LoadWindowState(); }

    private void WindowLoaded(object pSender, RoutedEventArgs pRoutedEventArgs) { if (Settings.WindowState == WindowState.Maximized) mWindow.WindowState = Settings.WindowState; }

    #endregion Methods

    #region Nested Types

    public class WindowApplicationSettings : ApplicationSettingsBase
    {
        #region Constructors

        public WindowApplicationSettings(WindowSettings pWindowSettings) { }

        #endregion Constructors

        #region Properties

        [UserScopedSetting] public Rect Location {
            get {
                if (this["Location"] != null) return ((Rect) this["Location"]);
                return Rect.Empty;
            }
            set { this["Location"] = value; }
        }

        [UserScopedSetting] public WindowState WindowState {
            get {
                if (this["WindowState"] != null) return (WindowState) this["WindowState"];
                return WindowState.Normal;
            }
            set { this["WindowState"] = value; }
        }

        #endregion Properties
    }

    #endregion Nested Types
}
}

3

Bunu çözmenin varsayılan yolu, ayarlar dosyalarını kullanmaktır. Ayarlar dosyalarındaki sorun, tüm ayarları tanımlamanız ve verileri kopyalayan kodu kendi başınıza yazmanız gerektiğidir. Takip etmeniz gereken çok sayıda mülkünüz varsa oldukça sıkıcı.

Bunun için oldukça esnek ve kullanımı çok kolay bir kitaplık yaptım, ona sadece hangi nesnenin hangi özelliklerini izleyeceğini söyleyin ve gerisini o halleder. İsterseniz boktan şeyleri de yapılandırabilirsiniz.

Kitaplığın adı Jot (github) , işte onun hakkında yazdığım eski bir CodeProject makalesi .

Bir pencerenin boyutunu ve konumunu takip etmek için bunu şu şekilde kullanabilirsiniz:

public MainWindow()
{
    InitializeComponent();

    _stateTracker.Configure(this)
        .IdentifyAs("MyMainWindow")
        .AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
        .RegisterPersistTrigger(nameof(Closed))
        .Apply();
}

Nota ve ayar dosyalarına karşı: Jot ile çok daha az kod vardır ve her özellikten yalnızca bir kez bahsetmeniz gerektiğinden hataya çok daha az meyillidir . Ayarlar dosyalarıyla, her bir özelliği 5 kez belirtmeniz gerekir : bir kez özelliği açıkça oluşturduğunuzda ve değerleri ileri geri kopyalayan kodda ek olarak dört kez.

Depolama, serileştirme vb. Tamamen yapılandırılabilir. Ayrıca, IOC'yi kullanırken, izlemeyi çözdüğü tüm nesnelere otomatik olarak uygulayacak şekilde bağlayabilirsiniz, böylece bir mülkü kalıcı kılmak için tek yapmanız gereken, üzerine bir [İzlenebilir] özniteliği eklemektir.

Bütün bunları yazıyorum çünkü kütüphanenin birinci sınıf olduğunu düşünüyorum ve bu konuda ağzımdan çıkmak istiyorum.


Güzel, bunun için teşekkürler - Kod parçacığını yeni bir sınıfta, programın adını temel alan bir yolla durum izleyiciyi kurmak için kullandım. Bundan sadece bir satır yazmak zorunda ve tüm pencere özellikleri işlenir
Awesomeness

1

Bunu yapan hızlı bir ders yazdım. İşte adı şöyle:

    public MainWindow()
    {
        FormSizeSaver.RegisterForm(this, () => Settings.Default.MainWindowSettings,
                                   s =>
                                   {
                                       Settings.Default.MainWindowSettings = s;
                                       Settings.Default.Save();
                                   });
        InitializeComponent();
        ...

Ve işte kod:

public class FormSizeSaver
{
    private readonly Window window;
    private readonly Func<FormSizeSaverSettings> getSetting;
    private readonly Action<FormSizeSaverSettings> saveSetting;
    private FormSizeSaver(Window window, Func<string> getSetting, Action<string> saveSetting)
    {
        this.window = window;
        this.getSetting = () => FormSizeSaverSettings.FromString(getSetting());
        this.saveSetting = s => saveSetting(s.ToString());

        window.Initialized += InitializedHandler;
        window.StateChanged += StateChangedHandler;
        window.SizeChanged += SizeChangedHandler;
        window.LocationChanged += LocationChangedHandler;
    }

    public static FormSizeSaver RegisterForm(Window window, Func<string> getSetting, Action<string> saveSetting)
    {
        return new FormSizeSaver(window, getSetting, saveSetting);
    }


    private void SizeChangedHandler(object sender, SizeChangedEventArgs e)
    {
        var s = getSetting();
        s.Height = e.NewSize.Height;
        s.Width = e.NewSize.Width;
        saveSetting(s);
    }

    private void StateChangedHandler(object sender, EventArgs e)
    {
        var s = getSetting();
        if (window.WindowState == WindowState.Maximized)
        {
            if (!s.Maximized)
            {
                s.Maximized = true;
                saveSetting(s);
            }
        }
        else if (window.WindowState == WindowState.Normal)
        {
            if (s.Maximized)
            {
                s.Maximized = false;
                saveSetting(s);
            }
        }
    }

    private void InitializedHandler(object sender, EventArgs e)
    {
        var s = getSetting();
        window.WindowState = s.Maximized ? WindowState.Maximized : WindowState.Normal;

        if (s.Height != 0 && s.Width != 0)
        {
            window.Height = s.Height;
            window.Width = s.Width;
            window.WindowStartupLocation = WindowStartupLocation.Manual;
            window.Left = s.XLoc;
            window.Top = s.YLoc;
        }
    }

    private void LocationChangedHandler(object sender, EventArgs e)
    {
        var s = getSetting();
        s.XLoc = window.Left;
        s.YLoc = window.Top;
        saveSetting(s);
    }
}

[Serializable]
internal class FormSizeSaverSettings
{
    public double Height, Width, YLoc, XLoc;
    public bool Maximized;

    public override string ToString()
    {
        using (var ms = new MemoryStream())
        {
            var bf = new BinaryFormatter();
            bf.Serialize(ms, this);
            ms.Position = 0;
            byte[] buffer = new byte[(int)ms.Length];
            ms.Read(buffer, 0, buffer.Length);
            return Convert.ToBase64String(buffer);
        }
    }

    internal static FormSizeSaverSettings FromString(string value)
    {
        try
        {
            using (var ms = new MemoryStream(Convert.FromBase64String(value)))
            {
                var bf = new BinaryFormatter();
                return (FormSizeSaverSettings) bf.Deserialize(ms);
            }
        }
        catch (Exception)
        {
            return new FormSizeSaverSettings();
        }
    }
}

window.Intitialized window.Loaded bkz olmalıdır mostlytech.blogspot.com/2008/01/...
Gleb Sevruk

@Gleb, bence ikisi de çalışıyor. Initialized'da sorun mu yaşıyorsunuz?
tster

Evet, çünkü sadece başlatılmış olayı kullanırsanız büyütülmüş pencere yanlış ekranda olacaktır. Yaptığım şey işe yarıyor gibi görünüyor: Artık Loaded etkinliğine de abone oluyorum. _Window.WindowState = s.Maximized? WindowState.Maximized: WindowState.Normal; "Loaded" olay işleyicisinin içindeki satır. window.Initialized + = InitializedHandler; window.Loaded + = LoadedHandler; btw: Bu yaklaşımı beğendim
Gleb Sevruk

1

Bir var Nuget Projesi RestoreWindowPlace görmek github bir XML dosyasındaki bilgileri kaydetme, sizin için tüm bu yok.

Bir pencerede çalışmasını sağlamak için aramak kadar basit:

((App)Application.Current).WindowPlace.Register(this);

Uygulamada, pencerelerinizi yöneten sınıfı yaratırsınız. Daha fazla bilgi için yukarıdaki github bağlantısına bakın.


0

Bunu beğenebilirsin:

public class WindowStateHelper
{
    public static string ToXml(System.Windows.Window win)
    {
        XElement bounds = new XElement("Bounds");
        if (win.WindowState == System.Windows.WindowState.Maximized)
        {
            bounds.Add(new XElement("Top", win.RestoreBounds.Top));
            bounds.Add(new XElement("Left", win.RestoreBounds.Left));
            bounds.Add(new XElement("Height", win.RestoreBounds.Height));
            bounds.Add(new XElement("Width", win.RestoreBounds.Width));
        }
        else
        {
            bounds.Add(new XElement("Top", win.Top));
            bounds.Add(new XElement("Left", win.Left));
            bounds.Add(new XElement("Height", win.Height));
            bounds.Add(new XElement("Width", win.Width));
        }
        XElement root = new XElement("WindowState",
            new XElement("State", win.WindowState.ToString()),
            new XElement("Visibility", win.Visibility.ToString()),
            bounds);

        return root.ToString();
    }

    public static void FromXml(string xml, System.Windows.Window win)
    {
        try
        {
            XElement root = XElement.Parse(xml);
            string state = root.Descendants("State").FirstOrDefault().Value;
            win.WindowState = (System.Windows.WindowState)Enum.Parse(typeof(System.Windows.WindowState), state);

            state = root.Descendants("Visibility").FirstOrDefault().Value;
            win.Visibility = (System.Windows.Visibility)Enum.Parse(typeof(System.Windows.Visibility), state);

            XElement bounds = root.Descendants("Bounds").FirstOrDefault();
            win.Top = Convert.ToDouble(bounds.Element("Top").Value);
            win.Left = Convert.ToDouble(bounds.Element("Left").Value);
            win.Height = Convert.ToDouble(bounds.Element("Height").Value);
            win.Width = Convert.ToDouble(bounds.Element("Width").Value);
        }
        catch (Exception x)
        {
            System.Console.WriteLine(x.ToString());
        }
    }
}

Uygulama kapandığında:

        Properties.Settings.Default.Win1Placement = WindowStateHelper.ToXml(win1);
        Properties.Settings.Default.Win2Placement = WindowStateHelper.ToXml(win2);
        ...

Uygulama başladığında:

        WindowStateHelper.FromXml(Properties.Settings.Default.Win1Placement, win1);
        WindowStateHelper.FromXml(Properties.Settings.Default.Win2Placement, win2);
        ...

0

Varsayılan Ayarlarınızda WindowXml adlı bir dize oluşturun.

Pencere boyutunu ve konumunu geri yüklemek ve kaydetmek için Pencere Yüklendi ve Kapanış etkinliklerinizde bu uzantı yöntemini kullanın.

using YourProject.Properties;
using System;
using System.Linq;
using System.Windows;
using System.Xml.Linq;

namespace YourProject.Extensions
{
    public static class WindowExtensions
    {
        public static void SaveSizeAndLocation(this Window w)
        {
            try
            {
                var s = "<W>";
                s += GetNode("Top", w.WindowState == WindowState.Maximized ? w.RestoreBounds.Top : w.Top);
                s += GetNode("Left", w.WindowState == WindowState.Maximized ? w.RestoreBounds.Left : w.Left);
                s += GetNode("Height", w.WindowState == WindowState.Maximized ? w.RestoreBounds.Height : w.Height);
                s += GetNode("Width", w.WindowState == WindowState.Maximized ? w.RestoreBounds.Width : w.Width);
                s += GetNode("WindowState", w.WindowState);
                s += "</W>";

                Settings.Default.WindowXml = s;
                Settings.Default.Save();
            }
            catch (Exception)
            {
            }
        }

        public static void RestoreSizeAndLocation(this Window w)
        {
            try
            {
                var xd = XDocument.Parse(Settings.Default.WindowXml);
                w.WindowState = (WindowState)Enum.Parse(typeof(WindowState), xd.Descendants("WindowState").FirstOrDefault().Value);
                w.Top = Convert.ToDouble(xd.Descendants("Top").FirstOrDefault().Value);
                w.Left = Convert.ToDouble(xd.Descendants("Left").FirstOrDefault().Value);
                w.Height = Convert.ToDouble(xd.Descendants("Height").FirstOrDefault().Value);
                w.Width = Convert.ToDouble(xd.Descendants("Width").FirstOrDefault().Value);
            }
            catch (Exception)
            {
            }
        }

        private static string GetNode(string name, object value)
        {
            return string.Format("<{0}>{1}</{0}>", name, value);
        }
    }
}

0

Lance Cleveland'ın cevabını kullanıyorum ve Ayarı bağlıyorum. Ancak Penceremin Ekran dışında kalmasını önlemek için biraz daha Kod kullanıyorum.

private void SetWindowSettingsIntoScreenArea()
{
    // first detect Screen, where we will display the Window
    // second correct bottom and right position
    // then the top and left position.
    // If Size is bigger than current Screen, it's still possible to move and size the Window

    // get the screen to display the window
    var screen = System.Windows.Forms.Screen.FromPoint(new System.Drawing.Point((int)Default.Left, (int)Default.Top));

    // is bottom position out of screen for more than 1/3 Height of Window?
    if (Default.Top + (Default.Height / 3) > screen.WorkingArea.Height)
        Default.Top = screen.WorkingArea.Height - Default.Height;

    // is right position out of screen for more than 1/2 Width of Window?
    if (Default.Left + (Default.Width / 2) > screen.WorkingArea.Width)
        Default.Left = screen.WorkingArea.Width - Default.Width;

    // is top position out of screen?
    if (Default.Top < screen.WorkingArea.Top)
        Default.Top = screen.WorkingArea.Top;

    // is left position out of screen?
    if (Default.Left < screen.WorkingArea.Left)
        Default.Left = screen.WorkingArea.Left;
}

0

RandomEngys'in parlak cevabına dayanarak daha genel bir çözüm yaptım. Konumu çalışan klasördeki dosyaya kaydeder ve oluşturduğunuz her yeni pencere için yeni özellikler oluşturmanız gerekmez. Bu çözüm, arkasındaki kodda minimum kodla benim için harika çalışıyor.

using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Interop;
using System.Xml;
using System.Xml.Serialization;

namespace WindowPlacementNameSpace
{

    // RECT structure required by WINDOWPLACEMENT structure
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;

        public RECT(int left, int top, int right, int bottom)
        {
            this.Left = left;
            this.Top = top;
            this.Right = right;
            this.Bottom = bottom;
        }
    }

    // POINT structure required by WINDOWPLACEMENT structure
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public POINT(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    }

    // WINDOWPLACEMENT stores the position, size, and state of a window
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct WINDOWPLACEMENT
    {
        public int length;
        public int flags;
        public int showCmd;
        public POINT minPosition;
        public POINT maxPosition;
        public RECT normalPosition;
    }

    public static class WindowPlacement
    {
        private static readonly Encoding Encoding = new UTF8Encoding();
        private static readonly XmlSerializer Serializer = new XmlSerializer(typeof(WINDOWPLACEMENT));

        [DllImport("user32.dll")]
        private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);

        [DllImport("user32.dll")]
        private static extern bool GetWindowPlacement(IntPtr hWnd, out WINDOWPLACEMENT lpwndpl);

        private const int SW_SHOWNORMAL = 1;
        private const int SW_SHOWMINIMIZED = 2;

        private static void SetPlacement(IntPtr windowHandle, string placementXml)
        {
            if (string.IsNullOrEmpty(placementXml))
            {
                return;
            }

            byte[] xmlBytes = Encoding.GetBytes(placementXml);

            try
            {
                WINDOWPLACEMENT placement;
                using (MemoryStream memoryStream = new MemoryStream(xmlBytes))
                {
                    placement = (WINDOWPLACEMENT)Serializer.Deserialize(memoryStream);
                }

                placement.length = Marshal.SizeOf(typeof(WINDOWPLACEMENT));
                placement.flags = 0;
                placement.showCmd = (placement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWNORMAL : placement.showCmd);
                SetWindowPlacement(windowHandle, ref placement);
            }
            catch (InvalidOperationException)
            {
                // Parsing placement XML failed. Fail silently.
            }
        }

        private static string GetPlacement(IntPtr windowHandle)
        {
            WINDOWPLACEMENT placement;
            GetWindowPlacement(windowHandle, out placement);

            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8))
                {
                    Serializer.Serialize(xmlTextWriter, placement);
                    byte[] xmlBytes = memoryStream.ToArray();
                    return Encoding.GetString(xmlBytes);
                }
            }
        }
        public static void ApplyPlacement(this Window window)
        {
            var className = window.GetType().Name;
            try
            {
                var pos = File.ReadAllText(Directory + "\\" + className + ".pos");
                SetPlacement(new WindowInteropHelper(window).Handle, pos);
            }
            catch (Exception exception)
            {
                Log.Error("Couldn't read position for " + className, exception);
            }

        }

        public static void SavePlacement(this Window window)
        {
            var className = window.GetType().Name;
            var pos =  GetPlacement(new WindowInteropHelper(window).Handle);
            try
            {
                File.WriteAllText(Directory + "\\" + className + ".pos", pos);
            }
            catch (Exception exception)
            {
                Log.Error("Couldn't write position for " + className, exception);
            }
        }
        private static string Directory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

    }
}

Arkanızdaki kodunuzda bu iki yöntemi ekleyin

///This method is save the actual position of the window to file "WindowName.pos"
private void ClosingTrigger(object sender, EventArgs e)
{
    this.SavePlacement();
}
///This method is load the actual position of the window from the file
protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    this.ApplyPlacement();
}

xaml penceresinde bunu ekle

Closing="ClosingTrigger"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.