65.9K
CodeProject 正在变化。 阅读更多。
Home

在 WinForms 应用程序中管理数据(无需数据库)

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.81/5 (13投票s)

2008年6月6日

CPOL

12分钟阅读

viewsIcon

61879

downloadIcon

3046

本文介绍了一种构建应用程序的方法,该应用程序可以在不依赖数据库的情况下收集、存储和检索数据。

BirdWatcher

引言

本文介绍了一种构建应用程序的方法,该应用程序可以在不依赖数据库的情况下收集、存储和检索数据。如果您需要存储少量数据,您的用户不会与其他用户共享数据,并且您不需要后端有完整的关系数据库,那么本文可能会让您感兴趣。

本文围绕一个演示项目构建,该项目允许用户存储在观鸟过程中收集的一些信息;当然,同样的方法也可以用于处理联系信息、库存、邮票收藏、钱币收藏、电影收藏,或者您感兴趣的任何其他内容。

BirdWatcher
图 1:应用程序主窗体。

该应用程序提供以下功能

  • 创建鸟类数据文件。
  • 向鸟类数据文件中添加鸟类。
  • 从鸟类数据文件中删除鸟类。
  • 按名称搜索特定鸟类。
  • 创建和编辑鸟类详细信息。
    • 鸟名
    • 鸟类性别
    • 鸟类栖息地
    • 鸟类行为
    • 观察日期
    • 观察时间
    • 鸟类图片
  • 保存鸟类数据文件。
  • 重新打开鸟类数据文件。
  • 遍历鸟类数据文件中的所有鸟类。
  • 查看鸟类数据文件中的所有鸟类列表。

应用程序中使用的这些方法仅仅代表了一种做事的方式;正如 .NET 世界中的大多数事物一样,有几种替代方法,如果您愿意,可以修改代码以使用其他方法之一来处理数据。

BirdWatcher
图 2:查找鸟类。


BirdWatcher
图 3:列出所有鸟类。

入门

此下载包含一个解决方案,其中包含一个名为 BirdWatcher 的 WinForms 项目;该项目包含三个窗体(主窗体、搜索窗体和用于显示鸟类总列表的窗体)、一个可序列化的类 BirdData.cs(用于包含与鸟类相关的数据)和一个名为 FileSerializer.cs 的类,其中包含两个 static 方法,用于序列化和反序列化鸟类数据(将其写入文件和从文件中读取)。

如果您在 Visual Studio 2008 中打开附加的项目,您应该会在解决方案资源管理器中看到以下内容

BirdWatcher
图 4:解决方案资源管理器。

代码:BirdData.cs

BirdData 类是用于存储应用程序中所有与鸟类相关数据的容器类。虽然此演示使用鸟类数据,但也可以轻松替换为对您更有用的内容。

该类以常规的默认导入开始

using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;

下一节包含命名空间和类声明。请注意,该类被声明为 serializableserializable 属性表示该类可以被序列化。

namespace BirdWatcher
{
    [Serializable]
    public class BirdData
    {

类中定义的区域声明了类内部使用的成员变量;任何外部公开的成员变量都可以通过 public 属性访问。

#region Member Variables

        private Guid mId;
        private string mBirdName;
        private string mGender;
        private string mLocation;
        private string mBehaviorObserved;
        private DateTime mDateViewed;
        private DateTime mTimeViewed;
        private byte[] mPicture;
        private string mPictureName;

#endregion

类中的下一段代码包含构造函数。定义了两个构造函数;一个默认构造函数,用于创建类的实例并为其分配一个内部 ID(作为 Guid)。第二个构造函数接受一个鸟名作为参数,调用时,该构造函数会生成一个 ID 并将鸟名属性分配给鸟名成员变量。

#region Constructors

        /// <summary>
        /// Default Constructor
        /// </summary>
        public BirdData()
        {
            mId = Guid.NewGuid();
        }

        /// <summary>
        /// Overloaded Constructor
        /// </summary>
        /// <param name="birdname"></param>
        public BirdData(string birdname)
        {
            mId = Guid.NewGuid();
            mBirdName = birdname;
        }

#endregion

此类的最后部分代码位于属性区域内;此区域包含用于访问成员变量的所有属性。请注意,由于 ID 值始终由构造函数设置,因此该属性不提供 public 接口来将 Guid 设置为新值。

#region Properties

        public Guid ID
        {
            get
            {
                return mId;
            }
        }

        public string BirdName
        {
            get
            {
                return mBirdName;
            }
            set
            {
                mBirdName = value;
            }
        }

        public string Gender
        {
            get
            {
                return mGender;
            }
            set
            {
                mGender = value;
            }
        }

        public string Location
        {
            get
            {
                return mLocation;
            }
            set
            {
                mLocation = value;
            }
        }

        public string BehaviorObserved
        {
            get
            {
                return mBehaviorObserved;
            }
            set
            {
                mBehaviorObserved = value;
            }
        }

        public DateTime DateViewed
        {
            get
            {
                return mDateViewed;
            }
            set
            {
                mDateViewed = value;
            }
        }

        public DateTime TimeViewed
        {
            get
            {
                return mTimeViewed;
            }
            set
            {
                mTimeViewed = value;
            }
        }

        public byte[] Picture
        {
            get
            {
                return mPicture;
            }
            set
            {
                mPicture = value;
            }
        }

        public string PictureName
        {
            get
            {
                return mPictureName;
            }
            set
            {
                mPictureName = value;
            }
        }

#endregion
    }
}

以上是 BirdData 类的说明。

代码:主应用程序窗体 (Form1.cs)

鸟类追踪器主窗体包含以下控件

  • Menu
    • 文件
      • 新建
      • 打开
      • 保存
      • 另存为
      • 退出
    • 视图
      • 列出所有鸟类
  • 工具栏
    • 添加鸟类
    • 删除鸟类
    • 查找鸟类
    • 保存鸟类数据
    • 导航到上一只鸟
    • 导航到下一只鸟
    • 退出应用程序
  • 鸟名文本框控件
  • 鸟类性别组合框
  • 鸟类栖息地多行文本框
  • 鸟类行为多行文本框
  • 观察日期日期时间选择器
  • 观察时间日期时间选择器
  • 组容器
  • 图片框
  • 设置图片按钮


图 5:Form1.cs。

该类以常规的默认导入开始

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

下一节包含命名空间和类声明。

namespace BirdWatcher
{
    /// <summary>
    /// A simple project used to maintain data about a
    /// collection of birds (could be anything), and to
    /// display that data to the user, persist the data,
    /// and allow the user to recover and modify the
    /// data without using a database.
    /// </summary>
    public partial class Form1 : Form
    {

类中定义的区域声明了类内部使用的成员变量;任何外部公开的成员变量都可以通过 public 属性访问。每个声明旁边的注释描述了其用途。

#region Variable Declarations

        private List<BirdData> birds;   // a container for the bird collection
        BirdData currentBird;           // the current bird (displayed)
        string currentFilePath;         // the path to the bird data file
        int currentPosition;            // the position within the bird list
        bool dirtyForm;                 // mark the form dirty when changed

#endregion

下一段代码区域包含构造函数。初始化时,应用程序创建一个新的鸟类数据列表,创建一个新的鸟类数据对象,将日期和时间选择器控件设置为当前日期,将当前位置指示器设置为零,并将 dirty form Boolean 设置为 false

#region Constructor

        /// <summary>
        /// constructor initializes bird list and
        /// defaults values
        /// </summary>
        public Form1()
        {
            InitializeComponent();

            // create new bird data list
            // ready to write data
            birds = new List<BirdData>();
            currentBird = new BirdData();

            // set the date time pickers to now
            dtpDate.Value = DateTime.Now;
            dtpTime.Value = DateTime.Now;

            // init current position to zero
            currentPosition = 0;

            // mark form as not dirty
            dirtyForm = false;
        }

#endregion

下一个代码区域称为 Housekeeping。此区域包含一些用于操作应用程序的基本功能。第一个代码部分是退出工具栏按钮的点击事件处理程序;此函数仅调用退出菜单项选项的事件处理程序,而不是在两个函数中复制代码。

#region Housekeeping

        /// <summary>
        /// Exit the application
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbExit_Click(object sender, EventArgs e)
        {
            // call the menu function
            exitToolStripMenuItem_Click(this, new EventArgs());
        }

下一节代码是退出菜单选项的点击事件处理程序。此代码首先检查窗体是否被标记为 dirty(基于用户在应用程序运行期间所做的更改);如果窗体是 dirty 并且用户尝试退出应用程序,则会向用户显示一个消息框,询问用户是否希望在不保存的情况下退出应用程序。如果用户表示更愿意在退出应用程序之前保存,应用程序将向用户显示保存文件对话框;否则,应用程序将退出。

        /// <summary>
        /// Exit the application
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (dirtyForm == true)
            {
                if (MessageBox.Show(this, "You have not saved the current bird data;
                  " + "would you like to save before exiting?", "Save Current Data",
                  MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
                {
                    saveToolStripMenuItem_Click(this, new EventArgs());
                }
                else
                {
                    Application.Exit();
                }
            }
            else
            {
                Application.Exit();
            }
        }

下一个方法用于清除主窗体控件中显示的所有信息。

        /// <summary>
        /// Clear all form fields
        /// </summary>
        public void ClearForm()
        {
            dirtyForm = true;

            txtBirdName.Text = string.Empty;
            txtLocation.Text = string.Empty;
            txtBehavior.Text = string.Empty;

            cboGender.SelectedIndex = -1;

            dtpDate.Value = DateTime.Now;
            dtpTime.Value = DateTime.Now;

            picBird.Image = null;
        }

窗体中的下一个函数用于设置当前鸟类的关联图像。由于我们正在向当前鸟类数据实例添加新数据,因此窗体被标记为 dirty – 这将允许退出应用程序的函数检查当前数据是否需要在退出应用程序之前保存。该函数使用打开文件对话框允许用户设置图像文件的路径;设置文件路径后;该函数打开文件,将其转换为字节数组并存储在当前鸟类数据对象的图像属性中。该函数最后设置窗体的图像以显示所选鸟类的图片。

        /// <summary>
        /// Load the image into the picture box
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSetImage_Click(object sender, EventArgs e)
        {
            dirtyForm = true;

            string imageFilePath = string.Empty;

            OpenFileDialog OpenFileDialog1 = new OpenFileDialog();
            OpenFileDialog1.Title = "Open Image File";
            OpenFileDialog1.Filter = "JPEG Documents (*.jpg)|*.jpg|Gif Files|*.gif";

            if (OpenFileDialog1.ShowDialog() ==
            System.Windows.Forms.DialogResult.Cancel)
            {
                return;
            }

            imageFilePath = OpenFileDialog1.FileName;
            if (String.IsNullOrEmpty(imageFilePath))
            {
                return;
            }

            if (System.IO.File.Exists(imageFilePath) == false)
            {
                return;
            }

            byte[] bArrImage = new byte[0];
            try
            {
                // convert Image to byte array and save in
                System.IO.FileStream fsImage = null;
                fsImage = System.IO.File.Open(imageFilePath, FileMode.Open,
                FileAccess.Read);
                bArrImage = new byte[fsImage.Length];
                fsImage.Read(bArrImage, 0, (int)fsImage.Length);
                fsImage.Close();

                currentBird.Picture = bArrImage;
                currentBird.PictureName = imageFilePath;

                MemoryStream ms = new MemoryStream(bArrImage);
                picBird.Image = Image.FromStream(ms);
                ms.Dispose();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message, "Error Storing Image");
            }
        }

下一个函数用于处理“新建”菜单选项的点击事件;此函数首先检查 dirty form Boolean ,以确定当前数据是否应在开始新的鸟类数据文件之前保存。如果当前窗体是 dirty;用户将被提示保存当前数据,否则,将创建一个新的鸟类数据集合,并且窗体将被清除所有先前的条目。

        /// <summary>
        /// Create a new bird data file
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (dirtyForm == true)
            {
                if (MessageBox.Show(this, "You have not saved the current bird data;
                                 " + "would you like to save before starting a new "
                                 + "bird database?", "Save Current Data",
                    MessageBoxButtons.YesNo) ==
                    System.Windows.Forms.DialogResult.Yes)
                {
                    saveToolStripMenuItem_Click(this, new EventArgs());
                }
                else
                {
                    // discard and start new document
                    birds = new List<BirdData>();
                    ClearForm();
                }
            }
            else
            {
                // start new document
                birds = new List<BirdData>();
                ClearForm();
            }
        }

接下来是打开文件菜单选项的点击事件处理程序;此函数在打开新的鸟类数据文件到应用程序之前也检查 dirty form。如果窗体不是 dirty,应用程序将调用 Open 函数,该函数将允许用户导航并打开一个文件进行查看或编辑。

        /// <summary>
        /// Open an existing bird data file
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openStripMenuItem2_Click(object sender, EventArgs e)
        {
            if (dirtyForm == true)
            {
               if (MessageBox.Show(this, "You have not saved the current bird data; "
               + "would you like to save before opening a different " +
               "bird database?", "Save Current Data", MessageBoxButtons.YesNo) ==
                    System.Windows.Forms.DialogResult.Yes)
                {
                    saveToolStripMenuItem_Click(this, new EventArgs());
                }
                else
                {
                    Open();
                }
            }
            else
            {
                Open();
            }
        }

接下来,open 方法使用打开文件对话框控件允许用户导航并选择一个鸟类数据文件。选择后,文件将被反序列化到本地鸟类集合中,并可供显示。

        /// <summary>
        /// Open an existing bird data file
        /// </summary>
        public void Open()
        {
            OpenFileDialog OpenFileDialog1 = new OpenFileDialog();
            OpenFileDialog1.Title = "Open BRD Document";
            OpenFileDialog1.Filter = "BRD Documents (*.brd)|*.brd";
            if (OpenFileDialog1.ShowDialog() ==
            System.Windows.Forms.DialogResult.Cancel)
            {
                return;
            }

            currentFilePath = OpenFileDialog1.FileName;
            if (String.IsNullOrEmpty(currentFilePath))
            {
                return;
            }

            if (System.IO.File.Exists(currentFilePath) == false)
            {
                return;
            }

            birds = FileSerializer.Deserialize(currentFilePath);

            // Load bird at position zero
            if (birds != null)
            {
                currentBird = birds.ElementAt<BirdWatcher.BirdData>(0);
                LoadCurrentBird();
                dirtyForm = false;
            }
        }

下一个是保存菜单选项点击事件处理程序。此函数使用保存文件对话框允许用户命名或设置文件的路径。一旦设置了文件路径,应用程序将序列化鸟类集合中包含的数据,并将其保存到磁盘。

        /// <summary>
        /// Save the existing bird data file
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveCurrentBird();

            if (String.IsNullOrEmpty(currentFilePath))
            {
                SaveFileDialog SaveFileDialog1 = new SaveFileDialog();

                try
                {
                    SaveFileDialog1.Title = "Save BRD Document";
                    SaveFileDialog1.Filter = "BRD Documents (*.brd)|*.brd";

                    if (SaveFileDialog1.ShowDialog() ==
                    System.Windows.Forms.DialogResult.Cancel)
                    {
                        return;
                    }
                }
                catch
                {
                    return;
                }

                currentFilePath = SaveFileDialog1.FileName;
                if (String.IsNullOrEmpty(currentFilePath))
                {
                    return;
                }
            }

            FileSerializer.Serialize(currentFilePath, birds);

            MessageBox.Show("File " + currentFilePath + " saved.", "File Saved.");

            dirtyForm = false;
        }

下一段代码非常类似于保存;它允许用户使用替换名称将当前鸟类数据文件保存到本地硬件。

        /// <summary>
        /// Save the existing bird data file with
        /// a new file name
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog SaveFileDialog1 = new SaveFileDialog();

            try
            {
                SaveFileDialog1.Title = "Save BRD Document";
                SaveFileDialog1.Filter = "BRD Documents (*.brd)|*.brd";

                if (SaveFileDialog1.ShowDialog() ==
                       System.Windows.Forms.DialogResult.Cancel)
                {
                    return;
                }
            }
            catch
            {
                return;
            }

            currentFilePath = SaveFileDialog1.FileName;

            if (String.IsNullOrEmpty(currentFilePath))
            {
                return;
            }

            FileSerializer.Serialize(currentFilePath, birds);

            MessageBox.Show("File " + currentFilePath + " saved.", "File Saved.");

            dirtyForm = false;
        }

接下来是工具栏的保存按钮;它仅调用保存菜单项点击事件来保存鸟类数据文件。

        /// <summary>
        /// Save the existing bird data file
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbSave_Click(object sender, EventArgs e)
        {
            saveToolStripMenuItem_Click(this, new EventArgs());
        }

保存当前鸟类函数用于将当前鸟类数据对象的值设置为与窗体控件的内容匹配。

        /// <summary>
        /// Set the current bird values to the form content;
        /// if the user navigates off the current bird, it will
        /// save the content
        /// </summary>
        private void SaveCurrentBird()
        {
            if(!String.IsNullOrEmpty(txtBirdName.Text))
            {
                try
                {
                    currentBird.BirdName = txtBirdName.Text;
                    currentBird.Location = txtLocation.Text;
                    currentBird.BehaviorObserved = txtBehavior.Text;

                    currentBird.Gender = cboGender.Text;

                    currentBird.DateViewed = dtpDate.Value;
                    currentBird.TimeViewed = dtpTime.Value;

                    // bird image byte array is set for current
                    // bird when image is set
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Error");
                }
            }
        }

下一个区域称为 Bird Data Management;在此部分内是用于管理鸟类数据和鸟类数据集合的方法。此区域中包含的第一个函数用于向集合中添加新鸟类。该函数保存当前鸟类,创建一个新的空鸟类对象,将新的鸟类数据对象添加到 birds 集合中,然后将窗体标记为 dirty。

#region Bird Data Management

        /// <summary>
        /// Add a new bird to the bird data list
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbAdd_Click(object sender, EventArgs e)
        {
            SaveCurrentBird();
            currentBird = new BirdData();
            ClearForm();
            birds.Add(currentBird);
            dirtyForm = true;
        }

下一个函数用于从集合中删除鸟类。删除鸟类后;当前位置将更新,并且窗体将使用替换的鸟类信息重新加载。

        /// <summary>
        /// Remove the current bird from the bird
        /// data list
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbRemoveBird_Click(object sender, EventArgs e)
        {
            birds.RemoveAt(currentPosition);

            if (currentPosition == 0)
                currentPosition++;
            else
                currentPosition--;

            currentBird = birds[currentPosition];
            LoadCurrentBird();
            dirtyForm = true;
        }

下一个函数用于支持查找特定鸟类。当点击事件处理程序执行时,将创建一个查找窗体(Form3)的新实例,并设置查找窗体的 BirdNameUpdated 事件的事件处理程序。

        /// <summary>
        /// Find a specific bird
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbFindBird_Click(object sender, EventArgs e)
        {
            Form3 f = new Form3(birds);
            f.BirdNameUpdated += new Form3.BirdNameUpdateHandler(FindBird);
            f.Show();
        }

下一个函数用于按名称查找特定鸟类。当查找窗体引发事件指示用户想要找到集合中某个特定名称的鸟类时,此函数将迭代集合直到找到匹配项,然后它将使该鸟类成为当前鸟类并更新窗体以显示该鸟类的信息。

        /// <summary>
        /// The bird finder code
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FindBird(object sender, BirdNameUpdateEventArgs e)
        {
            for (int i = 0; i < birds.Count; i++)
            {
                if (birds[i].BirdName == e.BirdName)
                {
                    currentBird = birds[i];
                    LoadCurrentBird();
                    currentPosition = i;
                }
            }
        }

下一个函数用于显示一个包含当前鸟类数据列表中所有鸟类的窗体。Form2 包含一个数据网格视图控件,它接受鸟类数据列表作为构造函数的参数。当创建窗体并传递当前鸟类数据的副本时,该数据将绑定到数据网格视图控件并显示给用户。

        /// <summary>
        /// List all of the birds in the bird
        /// data file
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listAllBirdsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form2 f = new Form2(birds);
            f.Show();
        }

下一个函数在当前鸟类更改时调用。它从当前鸟类对象重新加载所有窗体控件。

        /// <summary>
        /// Load the current bird into the form
        /// </summary>
        private void LoadCurrentBird()
        {
            try
            {
                txtBirdName.Text = currentBird.BirdName;
                txtLocation.Text = currentBird.Location;
                txtBehavior.Text = currentBird.BehaviorObserved;
            }
            catch { }

            try
            {
                cboGender.Text = currentBird.Gender;
            }
            catch { }

            try
            {
                dtpDate.Value = currentBird.DateViewed;
            }
            catch { }

            try
            {
                dtpTime.Value = currentBird.TimeViewed;
            }
            catch { }

            try
            {

                if (currentBird.Picture != null)
                {
                    MemoryStream ms = new MemoryStream(currentBird.Picture);
                    picBird.Image = Image.FromStream(ms);
                    ms.Dispose();
                }
                else
                {
                    picBird.Image = null;
                }
            }
            catch
            {
                picBird.Image = null;
            }
        }

此类中的下一个区域包含两个用于控制鸟类数据列表向前和向后导航的函数。无论哪种情况,都会通过调用 SaveCurrentBird 函数来保存当前鸟类。在本地保存当前鸟类后,将检查位置以查看它是否处于底部或顶部限制,如果可能,将递增或递减位置。一旦更新了当前位置,当前鸟类数据将被设置为更新位置处的鸟类数据,并重新加载窗体。

#region Navigation

        /// <summary>
        /// Navigate back to the previous bird
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbNavBack_Click(object sender, EventArgs e)
        {
            SaveCurrentBird();

            if (currentPosition != 0)
            {
                currentPosition--;
                currentBird = birds[currentPosition];
                LoadCurrentBird();
            }
        }

        /// <summary>
        /// Navigate forward to the next bird
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tsbNavForward_Click(object sender, EventArgs e)
        {
            SaveCurrentBird();

            if (currentPosition < birds.Count - 1)
            {
                currentPosition++;
                currentBird = birds[currentPosition];
                LoadCurrentBird();
            }
        }

#endregion

此类的最后一个代码区域用于响应更改将窗体标记为 dirty。请注意,而不是使用值更改事件来设置 dirty form,而是使用了其他事件,例如文本框控件的按键事件,以提供一个指示,说明是否发生了更改。原因是,如果打开鸟类数据文件并浏览列表,值将发生更改,并且窗体将被标记为 dirty,尽管实际上没有发生更改。

#region Dirty the Form

        /// <summary>
        /// Dirty the form if the user enters text into
        /// the bird name textbox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtBirdName_KeyPress(object sender, KeyPressEventArgs e)
        {
            dirtyForm = true;
        }

        /// <summary>
        /// Dirty the form if the user clicks on the gender
        /// combobox to change the value
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboGender_MouseClick(object sender, MouseEventArgs e)
        {
            dirtyForm = true;
        }

        /// <summary>
        /// Dirty the form if the user enters text into
        /// the location textbox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtLocation_KeyPress(object sender, KeyPressEventArgs e)
        {
            dirtyForm = true;
        }

        /// <summary>
        /// Dirty the form if the user enters text into
        /// the bird behavior textbox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtBehavior_KeyPress(object sender, KeyPressEventArgs e)
        {
            dirtyForm = true;
        }

        /// <summary>
        /// Dirty the form if the user picks a date from the
        /// control
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dtpDate_CloseUp(object sender, EventArgs e)
        {
            dirtyForm = true;
        }

        /// <summary>
        /// Dirty the form if the user picks a time from the
        /// control
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dtpTime_CloseUp(object sender, EventArgs e)
        {
            dirtyForm = true;
        }

#endregion

以上是应用程序主窗体代码的讨论。

代码:列出所有鸟类窗体 (Form2.cs)

用于显示当前鸟类数据列表中所有鸟类的窗体非常简单。该窗体包含一个数据网格视图控件,用于显示鸟类数据列表。构造函数已修改为接受鸟类数据列表作为参数,构造函数将数据网格视图控件绑定到鸟类数据列表,并隐藏第一列(包含用于唯一标识记录的 Guid)。

此类代码已全部提供

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace BirdWatcher
{
    /// <summary>
    /// This form class is used to display all of the
    /// current birds in a data grid view control.
    /// </summary>
    public partial class Form2 : Form
    {
        /// <summary>
        /// The constructor accepts the bird data
        /// as an argument; this list is set as
        /// the datasource for the datagridview control
        /// </summary>
        /// <param name="bd"></param>
        public Form2(List<BirdData> bd)
        {
            InitializeComponent();
            dataGridView1.DataSource = bd;

            // this is a guid to hide it
            dataGridView1.Columns[0].Visible = false;
        }
    }
}

以上是 Form2 类的说明。

代码:查找鸟类窗体 (Form3.cs)

此窗体用于向用户提供当前鸟类数据列表中所有鸟类名称的列表。用户可以查看和选择列表中的鸟类名称,然后单击窗体的查找按钮;这将引发一个事件,主窗体将使用该事件将匹配的鸟类加载到窗体中。

该类以常规的默认库导入、命名空间声明和类声明开始

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace BirdWatcher
{
    /// <summary>
    /// This form class displays a list of existing
    /// bird names for the user to pick from; once
    /// selected, an event will be raised with
    /// the selected bird name passed as an
    /// argument.  The main form will listen
    /// for an process this event to update
    /// the display of the current bird to match
    /// the search bird.
    /// </summary>
    public partial class Form3 : Form
    {

在类声明之后,声明了一个 delegate event ;这些用于在用户从窗体列表中选择鸟类并单击窗体的查找按钮时通知主窗体。BirdNameUpdateEventArgs 被声明为一个单独的类;该类将用于包含选定的鸟名,并在引发事件时将该信息提供给主窗体。

        // add a delegate
        public delegate void BirdNameUpdateHandler(object sender,
            BirdNameUpdateEventArgs e);

        // and associated event to notify
        // listeners when a bird name is
        // picked from this form's bird
        // name list
        public event BirdNameUpdateHandler BirdNameUpdated;

构造函数已修改为接受鸟类数据列表作为参数;每当创建窗体实例时,构造函数将遍历鸟类数据列表并将每个鸟名添加到用于显示鸟名的 listbox 控件中。

        /// <summary>
        /// Pass current bird data list to the
        /// constructor so that the form can
        /// generate a list of bird names for
        /// the user to choose from
        /// </summary>
        /// <param name="bd"></param>
        public Form3(List<BirdData> bd)
        {
            InitializeComponent();

            // iterate the bird data to add
            // each bird name to the bird
            // name list box control
            foreach (BirdData bird in bd)
                listBox1.Items.Add(bird.BirdName);
        }

查找按钮点击事件处理程序会创建一个事件参数实例,并将 listbox 控件的选定项添加到事件参数中。设置完成后,将引发事件,而引发事件将强制主窗体将选定鸟类的名称加载到窗体控件中。

        /// <summary>
        /// When the user clicks on the find button,
        /// raise an event so the main form will display
        /// the appropriate bird
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnFind_Click(object sender, EventArgs e)
        {
            // populate the argument list with the bird name
            BirdNameUpdateEventArgs args =
                new BirdNameUpdateEventArgs(listBox1.SelectedItem.ToString());

            // raise the event to pass the bird name back to the
            // main form for processing
            BirdNameUpdated(this, args);
        }
    }   // end class

BirdNameUpdateEventArgs 类用于包含鸟名,并在引发鸟名更新事件时将鸟名传递给主窗体。此类可以扩展以包含更多属性。

    /// <summary>
    /// Container for the bird name update event arguments;
    /// in this case there is only one argument, that being
    /// the selected name of a bird from the bird list
    /// </summary>
    public class BirdNameUpdateEventArgs : System.EventArgs
    {
        // add local member variable to hold text
        private string mBirdName;

        // class constructor
        public BirdNameUpdateEventArgs(string sBirdName)
        {
            this.mBirdName = sBirdName;
        }

        // Properties - Accessible by the listener
        public string BirdName
        {
            get
            {
                return mBirdName;
            }
        }
    }   // end class
}

以上是查找窗体类(Form3.cs)的讨论。

摘要

本文介绍了一种可以在不实际使用数据库支持的情况下,在 Winforms 应用程序中持久化和管理数据的方法。这种方法可能在许多不同的应用程序中有用,在这些应用程序中,用户不与其他用户共享信息。即使示例显示了管理鸟类信息集合的方法,它也可以用于任何其他目的,例如维护飞蝇钓鱼图案库、您喜欢的昆虫收藏、工具或设备库存等。

历史

  • 2008年6月3日:初始版本
© . All rights reserved.