لماذا لا يمكنك ربط حجم نموذج windows بإعدادات التطبيق؟

StackOverflow https://stackoverflow.com/questions/18585

سؤال

تحديث:تم الحل مع الكود

لقد نجحت في ذلك، راجع إجابتي أدناه للحصول على الكود ...

المشاركة الأصلية

كما أشار توندي في إجابته لي السؤال الأخير, ، يمكنك ربط كل شيء تقريبًا يتعلق بالتحكم في نماذج Windows بإعدادات التطبيق دون عناء.فهل لا توجد حقًا طريقة للقيام بذلك باستخدام حجم النموذج؟ هذا البرنامج التعليمي يقول أنك بحاجة إلى التعامل مع الحجم بشكل صريح حتى تتمكن من حفظ RestoreBounds بدلاً من الحجم إذا تم تكبير النافذة أو تصغيرها.ومع ذلك، كنت آمل أن أتمكن من استخدام خاصية مثل:

public Size RestoreSize
{
    get
    {
        if (this.WindowState == FormWindowState.Normal)
        {
            return this.Size;
        }
        else
        {
            return this.RestoreBounds.Size;
        }
    }
    set
    {
        ...
    }
}

لكن لا يمكنني رؤية طريقة لربط هذا في المصمم (الحجم مفقود بشكل ملحوظ من قائمة PropertyBinding).

هل كانت مفيدة؟

المحلول

لقد توصلت أخيرًا إلى فئة فرعية للنموذج تحل هذه المشكلة مرة واحدة وإلى الأبد.لتستخدمها:

  1. وراثة من RestorableForm بدلاً من النموذج.
  2. أضف رابطًا في (ApplicationSettings) -> (PropertyBinding) إلى WindowRestoreState.
  3. قم باستدعاء Properties.Settings.Default.Save() عندما تكون النافذة على وشك الإغلاق.

الآن سيتم تذكر موضع النافذة وحالتها بين الجلسات.باتباع الاقتراحات الواردة من الملصقات الأخرى أدناه، قمت بتضمين وظيفة ConstrainToScreen التي تتأكد من أن النافذة تناسب بشكل جيد شاشات العرض المتاحة عند استعادة نفسها.

شفرة

// Consider this code public domain. If you want, you can even tell
// your boss, attractive women, or the other guy in your cube that
// you wrote it. Enjoy!

using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

namespace Utilities
{
    public class RestorableForm : Form, INotifyPropertyChanged
    {
        // We invoke this event when the binding needs to be updated.
        public event PropertyChangedEventHandler PropertyChanged;

        // This stores the last window position and state
        private WindowRestoreStateInfo windowRestoreState;

        // Now we define the property that we will bind to our settings.
        [Browsable(false)]        // Don't show it in the Properties list
        [SettingsBindable(true)]  // But do enable binding to settings
        public WindowRestoreStateInfo WindowRestoreState
        {
            get { return windowRestoreState; }
            set
            {
                windowRestoreState = value;
                if (PropertyChanged != null)
                {
                    // If anybody's listening, let them know the
                    // binding needs to be updated:
                    PropertyChanged(this,
                        new PropertyChangedEventArgs("WindowRestoreState"));
                }
            }
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            WindowRestoreState = new WindowRestoreStateInfo();
            WindowRestoreState.Bounds
                = WindowState == FormWindowState.Normal ?
                  Bounds : RestoreBounds;
            WindowRestoreState.WindowState = WindowState;

            base.OnClosing(e);
        }

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

            if (WindowRestoreState != null)
            {
                Bounds = ConstrainToScreen(WindowRestoreState.Bounds);
                WindowState = WindowRestoreState.WindowState;
            }
        }

        // This helper class stores both position and state.
        // That way, we only have to set one binding.
        public class WindowRestoreStateInfo
        {
            Rectangle bounds;
            public Rectangle Bounds
            {
                get { return bounds; }
                set { bounds = value; }
            }

            FormWindowState windowState;
            public FormWindowState WindowState
            {
                get { return windowState; }
                set { windowState = value; }
            }
        }

        private Rectangle ConstrainToScreen(Rectangle bounds)
        {
            Screen screen = Screen.FromRectangle(WindowRestoreState.Bounds);
            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 Rectangle(left, top, width, height);
        }
    }
}

إعدادات الارتباطات المراجع

نصائح أخرى

السبب وراء عدم توفر خاصية Form.Size في واجهة مستخدم ربط الإعدادات هو أنه تم وضع علامة على هذه الخاصية DesignerSerializationVisibility.Hidden.هذا يعني أن المصمم لا يعرف كيفية إجراء تسلسل له، ناهيك عن إنشاء ربط بيانات له.بدلا من ذلك Form.ClientSize الخاصية هي التي يتم تسلسلها.

إذا حاولت أن تصبح ذكيًا بالربط موقع و حجم العميل, ، سترى مشكلة أخرى.عندما تحاول تغيير حجم النموذج من الحافة اليسرى أو العلوية، سترى سلوكًا غريبًا.يبدو أن هذا مرتبط بالطريقة التي يعمل بها ربط البيانات ثنائي الاتجاه في سياق مجموعات الخصائص التي تؤثر بشكل متبادل على بعضها البعض.كلاهما موقع و حجم العميل استدعاء في نهاية المطاف إلى طريقة مشتركة، سيت باوندز كور ().

أيضًا، ربط البيانات بخصائص مثل موقع و مقاس ليست فعالة.في كل مرة يقوم فيها المستخدم بنقل النموذج أو تغيير حجمه، يرسل Windows مئات الرسائل إلى النموذج، مما يتسبب في قيام منطق ربط البيانات بالكثير من المعالجة، في حين أن كل ما تريده حقًا هو تخزين الموضع والحجم الأخيرين قبل إغلاق النموذج.

هذه نسخة مبسطة جدًا لما أفعله:

private void MyForm_FormClosing(object sender, FormClosingEventArgs e)
{
    Properties.Settings.Default.MyState = this.WindowState;
    if (this.WindowState == FormWindowState.Normal)
    {
       Properties.Settings.Default.MySize = this.Size;
       Properties.Settings.Default.MyLoc = this.Location;
    }
    else
    {
       Properties.Settings.Default.MySize = this.RestoreBounds.Size;
       Properties.Settings.Default.MyLoc = this.RestoreBounds.Location;
    }
    Properties.Settings.Default.Save();
}

private void MyForm_Load(object sender, EventArgs e)
{
    this.Size = Properties.Settings.Default.MySize;
    this.Location = Properties.Settings.Default.MyLoc;
    this.WindowState = Properties.Settings.Default.MyState;
} 

لماذا هذه نسخة مبسطة للغاية؟لأن القيام بذلك بشكل صحيح هو أصعب بكثير مما يبدو :-)

حسنًا، لقد لعبت دورًا سريعًا في هذا الأمر وأنت على حق، بينما لا توجد طريقة مباشرة ربط حجم النموذج إلى AppSettings، يمكنك إضافة القيم الخاصة بك وتغيير الحجم عند التحميل.

ربما أوصي، إذا كانت هذه ميزة شائعة، أن تقوم بفئة فرعية من النموذج وتجعله يقوم تلقائيًا باختبار App.Config لإعدادات حجم النماذج.

(أو يمكنك لف الملف الخاص بك ..هل تريد الاستعلام عن ملف Xml "formname.settings.xml" أو شيء من هذا القبيل؟- التفكير بصوت عال!)..

هذا ما كان لدي (خشن جدًا، لا يوجد فحص للأخطاء وما إلى ذلك).

تكوين التطبيق

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
        <add key ="FormHeight" value="500" />
        <add key ="FormWidth" value="200"/>
    </appSettings>
</configuration>

رمز النموذج

    private void Form1_Load(object sender, EventArgs e)
    {
        string height = ConfigurationManager.AppSettings["FormHeight"];
        int h = int.Parse(height);
        string width = ConfigurationManager.AppSettings["FormWidth"];
        int w = int.Parse(width);
        this.Size = new Size(h, w);
    }

أحد الأسباب التي تجعلني أتخيل عدم السماح بربط الحجم هو أن الشاشة قد تتغير بين الجلسات.

قد يؤدي إعادة تحميل الحجم مرة أخرى عندما تنخفض الدقة إلى تجاوز شريط العنوان حدود الشاشة.

يجب عليك أيضًا أن تكون حذرًا من إعدادات الشاشات المتعددة، حيث قد لا تكون الشاشات متاحة عند تشغيل التطبيق في المرة التالية.

أنا أتفق مع إجابة روب كوبر.لكنني أعتقد أن مارتن قدم نقطة جيدة جدًا.لا شيء يضاهي أن يفتح المستخدمون تطبيقك ويكون التطبيق خارج الشاشة!

لذا، في الواقع، ستحتاج إلى الجمع بين الإجابتين ومراعاة أبعاد الشاشة الحالية قبل تحديد حجم النموذج الخاص بك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top