简体   繁体   中英

How do I validate a collection in a custom collectioneditor?

I have created a custom CollectionEditor but I want to validate my collection when the user clicks the 'OK' button. I've tried the following:

protected override CollectionForm CreateCollectionForm()
{
    _form = base.CreateCollectionForm();                        
    _form.FormClosing += _form_FormClosing;

    return _form;
}

So that when the user clicks OK it fires the _form_Closing event. This works however when I do this:

private void _form_FormClosing(object sender, FormClosingEventArgs e)
{
     e.Cancel = !Validate();                    
}

And Validate returns false (telling the form not to close) all of the existing members of the collection are removed from the UI . Surely the items of the collection shouldn't disappear from the UI ?

Is there something else I need to call?

OK so it's not elegant but it does work.

Get the ListBox like so

_listBox = _form.Controls[0].Controls[4] as ListBox;

Store it as a member variable and then handle the MouseDown event on the OK button like so

Button btnOK = _form.AcceptButton as Button;            
btnOK.MouseDown += btnOK_MouseDown;

Then create a list or array of objects in the class and copy them into the array on MouseDown (you can't do MouseClick as by then they are gone).

void btnOK_MouseDown(object sender, MouseEventArgs e)
{
    _objects = new List<object>();

    foreach (object listItem in _listBox.Items)
    {
        _objects.Add(listItem);
    }           
}       

Then on Form_Closing if the collection doesn't pass validation then add them back in.

if(!CheckValidEntities(_value as IEnumerable<Entity>))
{
    e.Cancel = true;

    foreach (object listItem in _objects)
    {
        _listBox.Items.Add(listItem);
    }                       
}

I don't love it and it is a little hacky but it seems to work.

Still a hack but this preserves the state of the dialog. This works no matter if the button was clicked with the mouse or the keyboard.

        protected override CollectionForm CreateCollectionForm()
        {
            this.Form = base.CreateCollectionForm();
            var okButton = this.Form.AcceptButton as Button;

            // replace the OK button current eventHandler.
            var okClickDelegate = this.RemoveClickEvent(okButton);
            okButton.Click += (sender, e) =>
            {
                // Validate your items
                var isValid = this.ValidateItems();
                if (isValid)
                {
                    okClickDelegate.DynamicInvoke(sender, e);
                }

                this.preventClose = !isValid;
            };
        }

        private void Form_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e)
        {
            e.Cancel = this.preventClose;

            this.preventClose = false;
        }

        /// <summary>
        /// Removes the click event handler of a button.
        /// </summary>
        /// <param name="b">The button to remove the click event.</param>
        /// <returns>A Delegate representing the remove event.</returns>
        private Delegate RemoveClickEvent(Button b)
        {
            FieldInfo f1 = typeof(Control).GetField("EventClick", BindingFlags.Static | BindingFlags.NonPublic);
            object obj = f1.GetValue(b);
            PropertyInfo pi = b.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
            EventHandlerList list = (EventHandlerList)pi.GetValue(b, null);

            var handler = list[obj];

            list.RemoveHandler(obj, handler);

            return handler;
        }

The function to remove the events was taken from: https://stackoverflow.com/a/91853/1698342

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM