Question

I'm working with COM object provided by Activator.

It also provide events when properties is changed there but my PropertyGrid can't update them in-time because it comes from another thread and I'm getting :

A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll
A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll
A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll

How to automate invoking property update when internal onChange is caused by external thread?

possible fix is: CheckForIllegalCrossThreadCalls = false;

But is it possible to handle this situation in proper way?

Was it helpful?

Solution

Let's say you are binding your object to a PropertyGrid, whenever a Property of your object get changed, it should fire a PropertyChanged event in the GUI thread, in order for the PropertyGrid to update properly.

It is your duty to marshal a Property setter to GUI thread. If you can have a link to any Control, use that Control to invoke. Otherwise, a general solution is create a dummy control at the beginning and use it for invoking.

public partial class ControlBase : UserControl
{
    /// <summary>
    /// Dummy control, use for invoking
    /// </summary>
    public static Control sDummyControl = null;

    /// <summary>
    /// Constructor
    /// </summary>
    public ControlBase()
    {
        InitializeComponent();

        if (sDummyControl == null)
        {
            sDummyControl = new Control();
            sDummyControl.Handle.ToString(); // Force create handle
        }
    }
}

In your parent object:

    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (PropertyChanged == null)
        {
            return;
        }
        Control c = ControlBase.sDummyControl;
        if (c == null)
        {
            PropertyChanged(sender, e);
        }
        else
        {
            if (c.InvokeRequired)
            {
                c.BeginInvoke(new PropertyChangedEventHandler(RaisePropertyChanged), new object[] { sender, e });
            }
            else
            {
                PropertyChanged(sender, e);
            }
        }
    }

In your object:

    public string Name
    {
        get { return _name; }
        set { _name = value; RaisePropertyChanged(this, new PropertyChangedEventArgs("Name")); }
    }

HTH, Huy

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top