windows窗体_如何保持Windows窗体状态

windows窗体

Sometimes when developing windows forms application, it becomes an important part of application design to persist the state of windows form after it is closed.

有时,在开发Windows窗体应用程序时,保持Windows窗体关闭后的状态成为应用程序设计的重要组成部分。

One such example that comes to my mind is an application called “Sticky Notes”.

我想到的一个这样的例子是一个名为“ Sticky Notes”的应用程序。

Here the user is expected to open a notepad which she can re-size as and when required, can write few notes on it and then close this form. The notes are to be saved in a persistent storage like Database or XML.

期望用户在此处打开一个记事本,她可以根据需要调整大小,可以在记事本上写一些便笺,然后关闭此表单。 注释将保存在数据库或XML等持久性存储中。

Next time when the user opens that sticky note, it should open in the same size and display the notes that were written by the user last time.

下次用户打开该便笺时,它应以相同的大小打开并显示用户上次写的便笺。

As far as persistence of the notes to Database and/or XML file is concerned, I know there are many ways to do it. This article however deals with the second part of the problem, i.e. persistence of the form state in the application.

至于数据库和/或XML文件的注释的持久性,我知道有很多方法可以做到。 但是,本文讨论了问题的第二部分,即应用程序中表单状态的持久性。

Some people might argue that if we can save note’s data in DB/XML we can also save form’s State. But, i personally feel that since form’s state is the data related to user interface, so it should be persisted somewhere in the application.

有人可能会争辩说,如果我们可以将注释的数据保存在DB / XML中,那么我们也可以保存表单的状态。 但是,我个人认为,由于表单的状态是与用户界面相关的数据,因此应将其保存在应用程序中的某个位置。

So let’s begin this tutorial by understanding the problem statement first:-

因此,让我们首先了解问题陈述来开始本教程:

The Problem Statement

问题陈述

During the flow of an application, a windows form is opened. The User the re-sizes the form, make some other activity with the form and closes the form. Next time when the user opens this same form again, the size of the form should be same as when the form was closed.

在应用程序流程中,将打开一个Windows窗体。 用户重新调整表单的大小,使用该表单进行其他活动并关闭该表单。 下次用户再次打开此相同表单时,表单的大小应与表单关闭时的大小相同。

Solution

Looking at the problem statement, as an application developer we can make out the following requirements:-

查看问题陈述,作为应用程序开发人员,我们可以满足以下要求:

1。 (1. )

We need a mechanism to save the size of the form before the form closes

我们需要一种机制来在表单关闭之前保存表单的大小

2。 (2. )

We need a mechanism to reload the saved state and apply this state to the form  before the form loads on screen.

我们需要一种机制来重新加载保存的状态,并在表单加载到屏幕上之前将此状态应用于表单。

Serialization Comes To Rescue

序列化得到拯救

If I have to put it in simple language, Serialization is the mechanism to convert an object graph to an array of bytes. De-Serialization is vice-verse.

如果必须用简单的语言来表达,序列化是一种将对象图转换为字节数组的机制。 反序列化是反之。

Right from the time .net came to existence; I personally feel serialization has been among the top features offered by the framework. It is truly very simple to serialize an object graph to array of bytes.

从.net诞生之日起; 我个人觉得序列化一直是该框架提供的主要功能之一。 将对象图序列化为字节数组确实非常简单。

The following few lines is just what we need to convert an object graph to memory stream:-

以下几行正是将对象图转换为内存流所需要的:

Stream memStream=new MemoryStream();
IFormatter formatter=new BinaryFormatter();
formatter.serialize(memStream, object);

Here is how to de-serialize it:-

以下是反序列化的方法:-

Object obj = formatter.deserialize(memStream);

So, let’s focus back on our problem. Let’s build the infrastructure to hold the persistence logic.

因此,让我们重新关注我们的问题。 让我们构建基础结构以容纳持久性逻辑。

A form state wrapper

表单状态包装器

Let’s first make a type which will hold the form’s state that can be persisted later on. Let’s name the class FormState and start with holding the form’s window state and form’s size in the FormState Type.  Next since we need to save this object through serialization, we need to mark it  as Serializable.

首先让我们创建一个将保留表单状态的类型,该类型以后可以保留。 让我们命名类FormState并从在FormState Type中保存表单的窗口状态和表单大小开始。 接下来,由于我们需要通过序列化保存该对象,因此需要将其标记为Serializable。

So the class looks like this:-

所以该类看起来像这样:

    [Serializable]
    internal class FormState
    {
        private readonly FormWindowState _windowState;
        private readonly Point _formSize;

        private FormState()
        {
        }

        public FormState(FormWindowState state, int width, int height)
        {
            _windowState = state;
            _formSize = new Point(width, height);
        }

        public FormWindowState WindowState
        {
            get { return _windowState; }
        }

        public Point Size
        {
            get { return _formSize; }
        }
     }

Also we have created a private parameter less constructor in FormState as is required at the time of serialization.

同样,我们在序列化时在FormState中创建了一个不带私有参数的构造函数。

A FormState collection

一个FormState集合

OK, so now we have a type to store form’s state information. Next let’s make a type to hold this state object of various forms. We need a dictionary where the key would be the form’s name and value would be an instance of FormState.

好,现在我们有了一个类型来存储表单的状态信息。 接下来,让我们创建一个类型来保存各种形式的状态对象。 我们需要一个字典,其中的键将是表单的名称,而值将是FormState的实例。

Let’s name the type as FormStateCollection as it will hold a collection of FormState Type.

我们将类型命名为FormStateCollection,因为它将保存FormState Type的集合。

Again this will also be marked serializable as this is the penultimate type that we are going to serialize and de-serialize. You can also say that this type is more of a state bag that will hold state information for all the forms.

同样,这也将被标记为可序列化,因为这是我们要序列化和反序列化的倒数第二种类型。 您也可以说这种类型更多的是状态包,它将保存所有表单的状态信息。

Here is how the type looks like:-

类型如下:

    [Serializable]
    class FormStateCollection
    {
        private IDictionary<string, FormState> _formPersistanceHandlers;
        public static FormStateCollection Instance { get; private set; }


        static FormStateCollection()
        {
            Instance =
                FileHelper.ReadFromFile<FormStateCollection>
                    (string.Format(Resources.FilePath,  Directory.GetCurrentDirectory())) ??
                new FormStateCollection();
        }
        
        #region Methods

        /// <summary>
        /// Adds Persistance Handler To The Dictionary(Thread Safe Way)
        /// </summary>
        /// <param name="formName"></param>
        /// <param name="handler"></param>
        [MethodImpl(MethodImplOptions.Synchronized)]
        public void Persist(string formName, FormState handler)
        {
            if(!IsInitialized()) _formPersistanceHandlers = new Dictionary<string, FormState>();

            if(ContainsKey(formName))
            {
                _formPersistanceHandlers[formName] = handler;
            }
            else
            {
                _formPersistanceHandlers.Add(formName, handler);
            }
            
        }

        /// <summary>
        /// Gets The Persistance Handler For Particular Form
        /// </summary>
        /// <param name="formName"></param>
        /// <returns></returns>
        public FormState ReadState(string formName)
        {
            if (!IsInitialized() || !ContainsKey(formName)) return null;

            return _formPersistanceHandlers[formName];
        }

        /// <summary>
        /// Checks Whether The Dictionary Has Been Initialized or Not
        /// </summary>
        /// <returns></returns>
        private bool IsInitialized()
        {
            return _formPersistanceHandlers != null;
        }

        /// <summary>
        /// If Dictionary Contains This Key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private bool ContainsKey(string key)
        {
            return _formPersistanceHandlers.ContainsKey(key);
        }

        #endregion
    }

The collection implements a singleton so that for entire application we can have a single collection that can be read from and written to by any form.

该集合实现一个单例,因此对于整个应用程序,我们可以有一个可以以任何形式读取和写入的单个集合。

The two most important behaviors of this collection are to save the form state and read the persisted state. The two methods namely Persist and ReadState are implementing the functionality.

此集合的两个最重要的行为是保存表单状态并读取持久状态。 Persist和ReadState这两个方法正在实现该功能。

OK, so we had enough of infrastructure, let’s put this to work and create our concrete types that forms are going to work with in the application.

好的,因此我们有足够的基础结构,让我们使用它来创建表单要在应用程序中使用的具体类型。

The PersistantForm

持久形式

If you could remember the initial requirements list that we made, we need to read from saved state before form load and save the state at the time when the form closes.

如果您还记得我们创建的初始需求列表,则需要在表单加载之前从保存的状态中读取信息,并在表单关闭时保存状态。

So we need to bind to the form’s load and close events. This means we need a form that can act as the base form for all the forms that need their state to be persisted.

因此,我们需要绑定到表单的load和close事件。 这意味着我们需要一个可以充当所有需要持久保存其状态的表单的基础表单的表单。

Let’s make an base form namely PersistantForm and bind to its load and closing events.

让我们创建一个基本表单,即PersistantForm并绑定到其load和close事件。

In the form load event handler, we will read from the saved state.

在表单加载事件处理程序中,我们将从已保存状态中读取。

In the form closing event handler, we will save the form’s current state.

在表单关闭事件处理程序中,我们将保存表单的当前状态。

Let’s have a look at this base form:-

让我们看一下这种基本形式:

public class PersistantForm : Form
    {
        public PersistantForm()
        {
            this.Load += PersistantFormBaseLoad;
            this.FormClosing += PersistantFormBaseFormClosing;
        }

        /// <summary>
        /// Update Our Persistable Forms Type & Serialize It
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void PersistantFormBaseFormClosing(object sender, FormClosingEventArgs e)
        {
            FormStateCollection.Instance.Persist(this.GetType().FullName, ReadCurrentState());
        }

        /// <summary>
        /// Apply Last Saved State To This Form
        /// </summary>
        /// <param name="state"></param>
        internal virtual void ApplyState(FormState state)
        {
            this.WindowState = state.WindowState;
            this.Size = new Size(state.Size);

            /********************************
             * You Can Also Read any other information
             * Persisted for this Form by calling
             * FormState ReadCustomState method like this:-
             * state.ReadCustomState<Rectangle>("key");
             ********************************/
        }

        /// <summary>
        /// Reads The Previous Saved State of this form
        /// </summary>
        /// <returns></returns>
        private FormState ReadLastState()
        {
            return FormStateCollection.Instance.ReadState(this.GetType().FullName);
        }

        

  /// <summary>
        /// Gets The Current State Of This Form
        /// </summary>
        /// <returns></returns>
        internal virtual FormState ReadCurrentState()
        {
            var currState = new FormState(this.WindowState, this.Size.Width, this.Size.Height);
            return currState;

            /********************************
             * You Can Also Persist any other information
             * by calling FormState AddCustomState method:-
             * currState.AddCustomState("key","value");
             ********************************/
        }
    } //End of class

What about other form states

那其他形式的状态呢

All looks good till now, but simply saving the form’s size and window state doesn’t help. We might need to store other information as well in our form type, so I have kept a dictionary in the FormState class to hold other state information.

到现在为止看起来一切都不错,但是简单地保存表单的大小和窗口状态并没有帮助。 我们可能还需要在表单类型中存储其他信息,因此我在FormState类中保留了一个词典来保存其他状态信息。

Also there are few methods to work around with this state dictionary.

同样,很少有方法可以处理此状态字典。

So that’s it folks, we have made an infrastructure which can be used to persist the Form’s state and then read from that state.

就是这样,伙计们,我们已经建立了可用于持久保存Form状态并从中读取状态的基础结构。

Go ahead and download the code attached.

继续并下载附带的代码。

Happy Programming..... FormPersist.zip FormPersist.zip

翻译自: https://www.experts-exchange.com/articles/10111/How-To-Persist-Windows-Form-State.html

windows窗体

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值