Winforms-based Editing

Topics: Developer Forum
Oct 7, 2008 at 12:08 AM
Hi

I have been working on a project that requires a website to be customised from a Winforms application. I found N2 CMS a couple of weeks ago, and I'm impressed with the power it offers developers. Most (if not all) of the CMS packages I've worked with require things to be implemented a certain way, and this can cause problems when a client asks for a feature that doesn't fit well into the CMS model.
N2 is definitely one of the best .NET CMS packages available.

One of the best features of N2 is the attribute-based editable properties. I was wondering if anyone else has tried adding an N2 Editor to a Windows application?
The approach I've taken is to modify all of the Editable attributes to include an additional Type in the constructor that references an appropriate Windows control.
I've managed to get the functionality of the editor working and I'm able to browse content items and edit/publish pages.
The problem now is I can't figure out how to set the layout of the controls automatically (I've tried FlowLayoutPanel and a custom recursive set layout method, but these both seemed to cause some problems for some of the controls).

I was hoping the N2 developer community here could offer suggestions/ideas that could help me get this up and running properly.

I also wanted to bounce an idea off Cristian ( hope you read this :) )  - 
A lot of the N2 core has explicit references to System.Web types and related methods (ie: IContainable.AddTo(Control container)). What if these were to be replaced with some kind of generic Mapping service?
For example:
IContainable.AddTo(object container) {
Resolve<IMappingService>().AddToContainer(container, this);
}
The mapping service would be responsible for determining what method needs to be called etc.
I think this could definitely make things easier for me and allow the N2 Editor to be hosted in any type of .NET environment (WebForms, WinForms, some other framework) with the appropriate mapping service.

I've only been working with N2 for a few weeks, so I'm not sure if this is even possible - but wanted to share my thoughts and ideas.

Thanks
Matthew
Coordinator
Oct 7, 2008 at 2:16 AM
Hi Matthew,

I tried to play with winforms and this simple scenario seems to work okay (I'm too web-impaired to really understand your problem):

        private void Form1_Load(object sender, EventArgs e)
        {
            FlowLayoutPanel frame = new FlowLayoutPanel();
            frame.Dock = DockStyle.Fill;
            frame.FlowDirection = FlowDirection.TopDown;
            Controls.Add(frame);

            AddTo(frame);
            AddTo(frame);
            AddTo(frame);
        }

        private void AddTo(Panel frame)
        {
            FlowLayoutPanel p = new FlowLayoutPanel();
            p.AutoSize = true;
           
           
            Label l = new Label();
            l.Text = "Label";
            p.Controls.Add(l);
            TextBox tb = new TextBox();
            p.Controls.Add(tb);

            frame.Controls.Add(p);
        }

I like your idea and I've actually given it a little though in the past. What I like about the current IEditable solution is that I most often only need to implement a single class to add a new type of field. It does rather tie it to webforms unfortunatly.

To bounce back a related idea. What do you think about a generic interface:

interface IContainable<T>
{
 AddTo(T container)
}

And morphing the editable attributes to implement one or more factory interfaces:

//web
interface IWebContatainableFactory
{
  IContainable<Web.UI.Control> GetContainable()
}

//winforms
interface IWinContatainableFactory
{
  IContainable<Win.Forms.Control> GetContainable()
}

It should be straightforward enough to return the attribute itself to support the current model:

class SomeEditable : IWebContatainableFactory
{
  IContainable<Web.UI.Control> GetContainable() { return this; }
}

And the additional interface can be implemented to support a winforms operation:

class SomeEditable : IWebContatainableFactory, IWinContatainableFactory
{
  IContainable<Web.UI.Control> GetContainable() { return this; }
  IWinContatainableFactory.IContainable<Win.Forms.Control> GetContainable() { return new WebFormsCode(); }
}

Anyway, I do think it's possible and I'm very interested in hearing about your experiences.
Oct 7, 2008 at 4:00 AM

Hi

Thanks for the reply. The layout problems seem to appear when trying to edit a Content Item that has child editors (ie: FAQ/Question list). I probably need to re-examine my current code and make some changes - I'll go through and try to sort it later tonight.

The Factory idea makes sense. I would hope that if a developer was trying to host the editor in a Winforms (or other environment), they would expect to have to make some modifications.

Am I right to assume that the ContainableFactory interfaces you described would allow me to extend the existing editable attributes and add the appropriate WinForms code?

class EditableWinTextBoxAttribute : EditableTextBoxAttribute, IWinContainableFactory
{
    IWinContatainableFactory.IContainable<Win.Forms.Control> GetContainable() 
    {  
         //method implementation 
    }
}

My attempt at getting a Winforms editor working meant I had to go through all the N2.Details attributes and duplicate the Web-specific methods. I would have preferred to leave the original N2 source intact and instead create an additional library containing the required Winforms code, but I decided to modify the N2 source to gain a better understanding of how N2 works. (I haven't looked at any alternative options so I'm not sure if this can be done with an additional library or not).

This method appears to be working quite well, but it required a lot of modification to the existing classes. I spent a lot of time cloning/updating the AddEditor/ModifyEditor/UpdateEditor methods. If these were updated to generic methods, it might make it a bit easier to extend.
Here's an example of what I mean, using the EditableWinTextBoxAttribute I described above:

N2's EditableTextBoxAttribute class:
UpdateEditor<TControl>(ContentItem item, TControl controlType) {
    // existing implementation
}

custom EditableWinTextBoxAttribute class:
UpdateEditor<TControl>(ContentItem item, TControl controlType) {
    if (typeof(TControl) == Win.Forms.Control) {
        // winforms implementation
    } else {
        // pass to base class
        base(item,controlType);
    }
}

N2 is designed to be web-based and I'm sure that 99% of users will only ever use the web-based editor - so increasing the complexity of N2 CMS and making developers have to add additional code just to support Winforms (when they don't want it) doesn't make a lot of sense. The factories you described avoid this problem, so it sounds like a good idea to me :)