Click here to Skip to main content
15,887,333 members
Articles / Programming Languages / C#
Article

Little Class Library to manage project file related Windows Form Application

Rate me:
Please Sign up or sign in to vote.
3.50/5 (10 votes)
20 Apr 2003CPOL7 min read 55K   1.3K   34   4
Did you ever want to code a little utility that should manage a project file?

Application build on this little framework focused on the next article

This screenshot shows a little app which is based on this class.

Index

Revision History

18.02.2003
10.02.2003
  • Well documented, NDoc generated help file available for download.
  • Add support to open file from command line (e.g. "Open" item in Context menu with %1) at startup.
  • Removed RecentProjectMenuItem Property with virtual method OnVisualizeRecentMenu which provides a ArrayList with Actions to build your own UI Recent Menu.
  • Add property EnableRecentMenu to disable this feature.
  • Add property RecentMenuMaxItems to control length of items.
15.01.2003
  • Bug fixed with form title, updated downloads.
21.12.2002
  • Final Release.

Introduction

Did you ever want to code a little utility that should manage a project file? I coded this on my own a few times, and now it’s time for me to create a class library. This article shows you how to use this class library, which enhances a normal windows form to a project file managing form. All the workflows needed like new, open, save, save as and close are implemented. It’s very easy to use this class, and you could develop straight forward, cause all the business logic is implemented in the base class, everything you need to do is override the methods and write your own important code, the code that is related to project specific implementation.

Key features are:

  • Standard implementation de/serialize IProject from/to xml file.
  • Using ActionList for UI Components, this means you could use your own classes for UI, only business logic is implemented
  • Components are enabled/disabled case sensitive to reflect project state
  • Needed workflows are implemented
  • You can control your program by overriding methods
  • After 5 minutes you are ready to implement the logic you need, you don’t have to manage project file states on your own
  • State of the art like “Recent Files” and standard shortcuts are implemented
  • You build your task on a tested framework in a short time

Background

This article is based on ActionLists for Windows.Forms by Serge Weinstock.

The majority of knowledge I've got about C# was from code project articles. I think it's very important to give something back to this community, so I started to write my own articles, hoping someone finds my articles and code useful.

Overview

The following graphic shows the concept behind this class. There is a UI component which represents your Form, and a project class which is nothing else than your project file. You inherit a Form from ProjectEnvironmentForm, put your UI controls as you like on it, attach the inherited Actions to your UI Controls, and on the fly you got New, Open, Save, Save As and Close Controls, with a nice Icon and the standard shortcuts, sound nice, eh ?

But at this time you’ve got no project file, sorry, class, that’s why there is a interface called IProject. Your project class inherit from IProject, implements all the methods and properties from this interface, and on the fly you’re able to manage the project class by the Form you just created a step before.

Image 2

Using the code

First of all you need to create a new windows forms project, or load your own project. Now you need to add a reference to the ProjectEnvironment.dll, otherwise you add the project to your solution by “Add Existing Project” and add a project related reference to the project you like to extend.

Now you create the project class, which inherits from ProjectEnvironment.Project.IProject. You need now to implement the required methods and properties specified by this interface. This looks like this:

How to inherit from IProject interface

C#
public class Project : ProjectEnvironment.Project.IProject
    {
        /// <summary>Indicates if project is dirty and must to be saved
        /// </summary>
        private bool isDirty;
        /// <summary>Title of project which is used on Save Dialog</summary>
        private string title;
        /// <summary>Event is fired if project is dirty</summary>
        public event EventHandler Dirty;

        public Project()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        /// <summary>Gets or sets the Dirty flag for this project</summary>
        public bool IsDirty
        {
            get
            {
                return this.isDirty;
            }
            set
            {
                this.isDirty = value;
            }
        }
        /// <summary>Reset the Dirty flag to false for this project, 
        /// called after Saving.</summary>
        public void ResetDirty()
        {
            IsDirty = false;
        }
        /// <summary>Called after loading this project file 
        /// from disk</summary>
        public void OnLoad()
        {
        }
        /// <summary>Called before saving this project 
        /// file to disk</summary>
        public void OnSave()
        {
        }
        /// <summary>Called after a new instance of this 
        /// project class is created</summary>
        public void OnNew()
        {
            this.title = "Write something here";
                    }
        /// <summary>Used to indicate this project for the user</summary>
        public string Title
        {
            get
            {
                return this.title;
            }
            set
            {
                this.title = value;
                // fire dirty event, to indicate that this project
                // is dirty and have to save.
                OnDirty();
            }
        }
        /// <summary>Called from properties set, to indicate 
        /// that a value changed occurred</summary>
        private void OnDirty()
        {
            // set dirty flag
            this.isDirty = true;
            // fire event to inform ProjectEnvironmentForm class 
            // and other consumer
            if (Dirty != null)
            {
                Dirty(this, EventArgs.Empty);
            }

    }

After you did this, you’ve got a valid project class which can be handled by ProjectEnvironmentForm.

How to inherit from ProjectEnvironmentForm

ProjectEnvironmentForm is the base windows form, you need to inherit from. There are three properties you need to set before this class can work properly. Your constructor should look like this:

C#
public class Form1 : ProjectEnvironment.ProjectEnvironmentForm
{
        public Form1()
        {
            InitializeComponent();
            // set type of your project class    
            this.ProjectType = typeof(Project);
            // set Extension Filter for FileOpen/Save Dialogs
            this.ShellExtensionFilter = "All files (*.*)|*.*";
            // enable "Recent Files" feature
            this.EnableRecentMenu= true;            
        }
}

The second thing you should is to override the property IsProjectValid, which means if a valid project file is loaded.

C#
public override bool IsProjectValid
{
    get
    {
        return base.IsProjectValid;
    }
    set
    {
        base.IsProjectValid = value;
        // implement your own code here to enable/disable UI Controls
    }
}

The third thing is to create a new CurrentProject property, which returns your own project type, otherwise you have to cast always from IProject to your project type.

C#
new public Data.Project CurrentProject
{
    get
    {
        return base.CurrentProject as Data.Project;
    }
}

If you like to use the Most Recent Items feature, you need to override method. You need to update your Menu to reflect current recent list provided as ArrayList.

C#
protected override void OnVisualizeRecentMenu(
     ArrayList actionListRecentItems)
{
    // clear old items
    this.menuRecentItems.MenuItems.Clear();
    // visualize items
    for(int i =0;i<actionListRecentItems.Count;i++)
    {
        MenuItem item = new MenuItem();
        ((Actions.Action)actionListRecentItems[i]).Parent.SetAction(
           item,actionListRecentItems[i]as Actions.Action);
        this.menuRecentItems.MenuItems.Add(item);
    }
}

How to attach your own UI controls to Actions

Now we need some Menu Item's and Toolbar Buttons to enable the user to control our project file. Your form now looks like every form, it’s a blank from. We need to do the following steps:

  • Add a Main Menu
  • Add File Menu Item to Main Menu
  • Add 6 MenuItem’s to File Menu Item
  • Add a Toolbar { or everything else that inherits from component }

Now you’ve got a form that looks funny, but not for long time. In the designer click now the first of the six Menu Item's, hit F4 for property dialog, and choose on “Action on action List” actNew. Do this for each of the six Menu Item's, until your form looks like the screenshot. The Exit Menu Item could not be attached to a base class Action, but you could extend the Action List with your own Actions, e.g. for the “Exit” Menu Item.

Image 3 Image 4

Now your Menu Item's are attached to the Actions, which means nothing else than the Menu Item's can now control the business logic implemented by the base class ProjectEnvironmentForm. The next step is to attach the same Actions to your Toolbar Buttons, set Appearance to Flat and add four buttons to it, now attach the Actions to the buttons.

Image 5

After these steps your form should have a UI that looks like this

Image 6

Now the user should be able to New, Open, Save, Save As and Close the project via MenuItem’s or the Toolbar Buttons. The MenuItem’s or Toolbar Buttons (Actions) should enable/disable to reflect the current project state. If the user changes a property of the project, the save action should be enabled, or if the user tries to close the form, the Save Dialog should appear.

Display project property on form

Now it’s time to implement your project related business logic, e.g. your project is based on Title property. Let me give you a small example of how you can do this as you can see it on my example project.

First of all you need to add Textbox and Label Controls to your form. Should look something like this:

Image 7

Now you extend your CurrentProject like this:

C#
public override bool IsProjectValid
    {
        get
        {
            return base.IsProjectValid;
        }
        set
        {
            base.IsProjectValid = value;
            // enable
            this.textBox1.Enabled = value;
            // data binding if project is valid (value == true)
            if (value)
            {
                // bind textbox to Title property
                this.textBox1.DataBindings.Add("Text",
                     this.CurrentProject,"Title");
            }
            else
            {
                this.textBox1.DataBindings.Clear();
                this.textBox1.Text = "";
            }
        }
    }

With these changes you enabled the Textbox to display the Title property of the current loaded/showed project file, otherwise if no valid project is displayed the Textbox is disabled.

Methods you could/should override to control your project

These methods could be overridden to control everything the way you like it or you need it for your current task. You could even call the base class methods with base.OnXX() and add your code to execute both, your own code and the base class code, as you know it from framework classes.
C#
// New
protected virtual Project.IProject OnNew()
{
}
protected virtual void OnNewBefore()
{
}
protected virtual void OnNewAfter()
{
}
// Close
protected virtual bool OnCloseBefore()
{
}
protected virtual bool OnClose()
{
}
protected virtual void OnCloseAfter()
{
}
// save
protected virtual bool OnSaveBefore(string path, object project)
{
}
protected virtual bool OnSaveAfter(string path, object project)
{
}
protected virtual bool OnSave(string path, object project)
{
}
// open
protected virtual void OnOpenBefore(string path)
{
}
protected virtual void OnOpenAfter(string path)
{
}
protected virtual Project.IProject OnOpen(string path)
{
}
    protected virtual void OnVisualizeRecentMenu(
          ArrayList actionListRecentItems)
    {
    }

What to do next ?

Now you should be able to use this little framework, to build your own project based tools and applications extremely fast. You can extend and alter the framework as you like, it should enhance only your start and guide you in a possible way to do stuff like this.

If you got any suggestions or bug-feedback feel free to drop me a note. Have fun with it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Switzerland Switzerland
My interest is in the future because I am going to spend the rest of my life there. (Charles Kettering)

Biography

  • 1996 - 1998 PC Board PPL, HTML, DHTML, Javascript and ASP
  • 1999 - 2001 coding Centura against Sql Database (SqlBase,MSSQL,Oracle)
  • 2002 - 2004 C# Windows Forms
  • 2005 - 2006 C# ASP.NET, Windows Forms
  • 2006 - 2009 C#, WCF, WF, WPF
  • 2010 - 2012 C#, Dynamics CRM, Sharepoint, Silverlight
  • 2013 - 2013 C#, WCF DS (OData), WF, WPF
  • 2014 - 2016 C#, Azure PaaS, Identity, OWIN, OData, Web Api
  • 2017 - now C#, aspnet.core, IdentityServer4, TypeScript & Angular @ Azure IaaS or PaaS

Interests

  • family & friends
  • chilaxing ,)
  • coding

Comments and Discussions

 
QuestionWhat about the little app Pin
aaroncampf22-Feb-12 9:55
aaroncampf22-Feb-12 9:55 
AnswerRe: What about the little app Pin
Chris Richner22-Feb-12 20:00
Chris Richner22-Feb-12 20:00 
Hi
Please check out this article Build solution from command line or with contexmenu item with Microsoft VS.NET[^]

The source code is long gone for the little demo app you saw on the picture, sorry

GeneralDisable menuitems Pin
Jan Wiggers29-Dec-02 23:19
Jan Wiggers29-Dec-02 23:19 
GeneralRe: Disable menuitems Pin
Chris Richner30-Dec-02 8:24
Chris Richner30-Dec-02 8:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.