C# WinForms control in .Net COM Server won't r

2019-08-01 00:06发布

问题:

I have a COM server app which uses some WinForms controls which, frankly, do not seem to be redrawing when their properties (Text, BackColor, etc) are changed.

I have tried invoking txtControlName.Invalidate() as well as .Update() and neither seem to be affecting anything.

It is a business requirement that we stick to .Net 2.0 and provide a visually responsive and interesting UI, and while I realize I can probably force redraws with WinAPI SendMessage() I would much rather have .Net handle all this stuff -- there are enough hacks in place and we don't want to add any more.

Finally, I wanted to note that the .Net COM server is hosted inside an unmanaged application.

Thanks!

Tom

Addendum:

At this time, the actual updating code looks like:

public void UpdateSt(int? seq, string text) {

    Control.CheckForIllegalCrossThreadCalls = true;

    if (this.lblText.InvokeRequired) {

        this.lblText.Invoke(new MethodInvoker(() => {

            UpdateSt(seq, text);

        }));

    } else {

        if (text != String.Empty) {

            lblText.Text = text;
            //WinAPI.InvalidateRect(lblText, true);
            lblText.Refresh();
            //WinAPI.SendMessage(lblText.Handle, (uint)WinAPI.WM.SETTEXT, 0, new StringBuilder(text));
            DebugTrace("lblText says '" + lblText.Text + "', is supposed to say '" + text + "'.");
        }

        if (imgSeq.HasValue) {

            // not implemented yet

        }

    }

}

Addendum #2:

Spy++ reports that the WM_SETTEXT call originating from .Net's Text setter is failing, much like my own WM_SETTEXT calls.

Addendum #3: SOLVED

Turns out the problem was a combination of a broken message pump and some P/Invoke calls that did more harm than good. As the library was started via COM there was no .Net message pump and adding Application.Run() inside a new thread allows everything to respond the way it should. It seems to be a good idea to make sure all forms-based interactions start from a thread with that call.

回答1:

The generic diagnostic is that there is something wrong with the message pump. You are not complaining that the controls do not paint themselves at all so it seems unlikely that this is completely broken. If this is an occasional painting problem then the diagnostic is that you've got a threading problem. In other words, you are updating the control properties, or calling Invalidate/Update, from the wrong thread.

Windows Forms has built-in diagnostics for this, active when a debugger is attached. Make sure you don't set the Control.CheckForIllegalCrossThreadCalls to false.

Next place to look is the message pump itself. When you display the forms with their Show() method instead of ShowDialog() then your unmanaged message pump will be dispatching messages. That has some undesirable side-effects by itself, keyboard accelerators won't work anymore, nor does tabbing. Check if the problem disappears if you use ShowDialog().


Your comment provides another hint at what might the problem. If you get False from InvokeRequired when you know that you're calling from another thread and you don't see any visible sign of your update then you are using the wrong Form object reference. Possibly one you created with the new operator. Make sure you use the existing one, Application.OpenForms[] can give you a reference if you have trouble getting one.