Change Target during Interception

May 30, 2010 at 3:09 PM
Edited May 30, 2010 at 3:12 PM

Hey Folks, I was trying to write a HandlerAttribute that I can use on any Form Type property on my windows desktop application.

Let me explain why I´m doing that.

Look the code bellow. If you open an Form instance, then close it and try to open it again, it will give you an error saying that, you can´t open because the Form instance is Disposed

    public partial class MainForm : Form
    {
        [Dependency]
        public LoginForm LoginFormInstance { get; set; }

        public MainForm()
        {
            this.InitializeComponent();
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            this.LoginFormInstance.Show(this);
        }

        private void OpenButton_Click(object sender, EventArgs e)
        {
            this.LoginFormInstance.Show(this);
        }

        private void CloseButton_Click(object sender, EventArgs e)
        {
            this.LoginFormInstance.Close();
        }
    }

So I thought to create a HandlerAttribute, that can detect if the Target was null or disposed and I put it on a base class, so all Forms can use it

    public class BaseForm : Form
    {
        [FormChecker(Order = 1)]
        public new void Show()
        {
            base.Show();
        }

        [FormChecker(Order = 1)]
        public new void Show(IWin32Window owner)
        {
            base.Show(owner);
        }
    }

I changed my Forms inheritance like

public partial class MainForm : BaseForm { ... }

public partial class LoginForm : BaseForm { ... }
Now with my handler I can intercept the call to Show Method and check if the instance is already disposed.
    [AttributeUsage(AttributeTargets.Method)]
    public class FormCheckerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container)
        {
            return new FormCheckerHandler(base.Order);
        }
    }

    public class FormCheckerHandler : ICallHandler
    {
        public Int32 Order { get; set; }

        public FormCheckerHandler(Int32 order)
        {
            this.Order = order;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            if (input.Target != null && input.Target is Form)
            {
                Form targetForm = input.Target as Form;
                if(targetForm == null || targetForm.IsDisposed)
                {
                    return getNext()(new FormMethodInvocation(input, input.Target), getNext);
                }
            }
            return getNext()(input, getNext);
        }
    }
As you can see, if the Target that is the Form property is null or IsDisposed I create a new MeThodInvocation where I will create a new target to be called bt the
GetNextHandlerDelegate delegate.

    public class FormMethodInvocation : IMethodInvocation 
    {
        public IMethodInvocation OriginalMethodInvocation { get; private set; }

        public FormMethodInvocation(IMethodInvocation methodInvocation, Object target)
        {
            this.OriginalMethodInvocation = methodInvocation;
            Form newForm = Activator.CreateInstance(target.GetType()) as Form;
            this.Target = newForm;
        }

        #region IMethodInvocation Members

        public IParameterCollection Arguments { get; set; }

        public IMethodReturn CreateExceptionMethodReturn(Exception ex)
        {
            return this.OriginalMethodInvocation.CreateExceptionMethodReturn(ex);
        }

        public IMethodReturn CreateMethodReturn(object returnValue, params object[] outputs)
        {
            return this.OriginalMethodInvocation.CreateMethodReturn(returnValue, outputs);
        }

        public IParameterCollection Inputs { get { return this.OriginalMethodInvocation.Inputs; } }

        public System.Collections.IDictionary InvocationContext { get { return this.OriginalMethodInvocation.InvocationContext; } }

        public MethodBase MethodBase { get { return this.OriginalMethodInvocation.MethodBase; } }

        public Object Target { get; private set; }

        #endregion
    }
But despite all my efforts the error still happen and I´m always getting a exception saying that the Form was already disposed.

Anyone call help me? Why my new Target with my new Form wasn´t the called object by GetNext Handler Delegate?
Thanks