Application hanging on Control.Invoke except when debugging - c#

I have my main form kicking off some background work using Delegate.BeginInvoke and within those delegates I am adding some rows to be displayed on a DataGridView on my main form. I have a backing dataset and a BindingSource attached to that, which I use as the source for my DataGridView.
Whenever I add a row, I do this:
ResultsDataTable.AddResultsRow(row);
RefreshDataGridView();
Where RefreshDataGridView() looks like this:
private void RefreshDataGridView()
{
if(InvokeRequired)
{
//I have tried dgvResults.Invoke() as well
dgvResults.BeginInvoke(new Action(() => RefreshDataGridView()));
}
else
{
dgvResults.Refresh(); //this is where it hangs
dgvResults.FirstDisplayedScrollingRowIndex = dgvResults.Rows.Count - 1;
}
}
It works well, when I add a new row it displays instantly and scrolls (despite my scrollbar not being drawn correctly but I can live with that) as expected, but only when I run the app through the debugger. When I start it without debugging, the application hangs whenever a row is added and it actually needs to scroll.
I've built the application in debug mode and run it without debugging, then let it get to the point where it hangs and attached the debugger to the process to see where it is happening (see comment in code above).
I know this is happening because my main thread is waiting for something but I have no clue what it is waiting for or how to find out.
Does anyone have any ideas?
Update: I started it without debugging then attached the debugger again, and found that the main thread is getting stuck updating a control, but I can't figure out which one.
Update 2: I got rid of the refresh and now it doesn't hang when adding the new row, but I can't resize my form at all without it hanging.
Update 3: It seemed to be hanging while trying to update the scrollbars of the data grid, so I encapsulated it in a panel and gave that scrollbars instead. With a bit of hacking to get the data grid to dynamically size itself based on the data it contains, it's a bit glitchy but no more deadlocks.

I had the same issue. You mentioned that your DataGridView has a bindingsource attached to it. If you are doing something to your source, then you are affecting the DataGridView. You will need to place that line of code that is modifying the source inside the BeginInvoke statement. Once I did that, the issue is gone.

Related

Application hangs when hosting managed control as CWnd

My application has ATL-based GUI (CWnd, CDialog,...) and it consists of multiple pages (CDialog). One of these pages is otherwise empty but it has a placeholder frame (CWnd) that resizes with the dialog. Everything is built as x64.
When the page loads, it asks for a control handle from managed (C#) side of the application using COM-interop, and adds the control to the dialog as CWnd that is created from that handle:
Managed implementation simplified:
// Class "ManagedControlProvider"
private Control myUserControl;
public long CreateControl()
{
myUserControl = /*Create some new inheritant of UserControl */
myUserControl.Dock = DockStyle.Fill;
return myUserControl.Handle.ToInt64();
}
Native side simplified:
// Call the managed class. Lifetime of m_pManagedControlProvider
// is ensured elsewhere.
LONGLONG lHandle = m_pManagedControlProvider->CreateControl();
// m_pUserCtrlAsCWnd is CWnd*
m_pUserCtrlAsCWnd = CWnd::FromHandle((HWND)lHandle);
m_pUserCtrlAsCWnd->SetParent(this);
// m_ControlFrame is just a native helper-CWnd the dialog that
// resizes with it a so gives us the size we want to set for the
// managed control. This code is also call in every resize -event.
RECT winRect;
m_ControlFrame.GetWindowRect(&winRect);
ScreenToClient(&winRect);
m_pUserCtrlAsCWnd->SetWindowPos(NULL,
winRect.left, winRect.top, winRect.right - winRect.left,
winRect.bottom - winRect.top, 0);
I have done this multiple times and it usually works exactly as is should. But sometimes, like now, I'm experiencing application hangs without any clear reason. With my current control this seems to happen roughly 5s after the focus is set to some other desktop application.
I have verified that the issue is not in the managed control's lifetime or GC. Also it's reproducible in debug build so optimizations are not to blame. When the hang occurs, I can attach debugger and see that some ATL loop keeps on going but that's the only piece of code I'm able to see in stack (imo this indicates that the message loop is somehow caught in infinite loop without interacting with my code).
Now for the dirties fix ever: I added a separate thread to my managed control that invokes this.Focus() every second on the UI thread. Obviously this is a ridiculous hack but it works as long as I pause the focusing everytime user opens combos etc (otherwise they get closed every second).
What am I doing wrong or what could cause this somewhat unpredictable behavior?
I don't know why or what it has to do with anything, but the application hang somehow originated from WM_ACTIVATE. So the solution was to override WINPROC at the main CDialog and block forwarding of that message. Everything has been working without any issues since then.
I'll not mark this as answer because I don't know why this solution works.

Odd behaviour when opening a WPF Window from WinForms

When displaying a WPF window from an Excel addin, I'm encountering odd behaviour whenever I show it with myWindow.Show() rather than myWindow.ShowDialog(). Thus far everything has worked fine when using the latter. However, it would be nice to be able to display a window such that the user can interact with Excel at the same time - i.e. the behaviour I'd expect from Show().
The problem is that controls in my form start acting very oddly quite quickly. ComboBox dropdowns collapse immediately, and textbox input ends up in whatever cell is selected in the Excel worksheet that's active.
I've noticed that with ShowDialog, Snoop is able to attach to my window as well, whereas with Show, I get an error amounting to "Could not find a PresentationSource to attach to". I'm not, however, completely sure if that's related.
Obviously one solution would be to stop directly showing a WPF window from WinForms; I expect the problem to largely go away if I change my window into a UserControl and chuck it into an ElementHost. However, I'd rather avoid that if I can.
Current code (roughly)
public void DoOpenWindow(Office.IRibbonControl button)
{
var myWindow = new myWindow();
// This hasn't addressed the issue, though may be sensible to include:
//ElementHost.EnableModelessKeyboardInterop(myWindow);
// This *also* didn't work, and essentially set my window to
// be always on top of Excel
//var hwSrc = HwndSource.FromVisual(myWindow );
//var ownerHelper = new WindowInteropHelper(myWindow );
//ownerHelper.Owner = (IntPtr)Globals.ThisAddIn.Application.Hwnd;
// with ShowDialog() this works fine...
myWindow .Show();
}
Current thoughts are:
I'm getting window messages from Excel forwarded to myWindow, some of which it isn't expecting.
Excel is intercepting messages meant for my window (keyboard and mouse), which is probably what ElementHost.EnableModelessKeyboardInterop(myWindow) is intended to solve (but either I'm using it wrong, or it's not the whole solution).

How do I avoid having my Rich Text Box, "scroll bar," freeze up?

My issue is in the .NET framework using C# to create a simple form application that contains a rich text box (RTB) control.
Briefly the issue I am experiencing is that when trying to clear the contents (.Text) of the RTB, the scroll bar doesn't go away. I would like to know if there is anything inherently wrong with the way I am using the RTB. I apologize, but the site will not allow me to post images yet. So if there is a misunderstanding regarding what "doesn't go away" means, please ask!
So first, I write data to the box using the following code snippet:
// append the new message
this.rtb_receive_0.Text += message;
this.rtb_receive_0.SelectionStart = this.rtb_receive_0.Text.Length;
this.rtb_receive_0.ScrollToCaret();
Later on, I clear the RTB contents (RTB.Text) with the following code:
this.rtb_receive_0.Text = String.Empty;
this.rtb_receive_0.Refresh();
In the above code I have attempted to fix my problem with the, "Refresh," method. However it does not seem to be doing the job.
When I clear the RTB contents, the scroll bar does not go away... I noticed that if I grab another window and drag it over the top of the application, that the frozen scroll bar disappears. Also, I can minimize the application, then maximize it again and the bar will disappear. There has to be a way to prevent this frozen scroll bar from happening in the first place though.
Per the answer, here was the fix to stop the bar from freezing up:
this.rtb_receive_0.Text = String.Empty;
this.rtb_receive_0.Clear();
this.rtb_receive_0.ScrollBars = RichTextBoxScrollBars.None;
this.rtb_receive_0.ScrollBars = RichTextBoxScrollBars.Vertical;
this.rtb_receive_0.Refresh();
Have you tried simply just programatically setting the Scrollbars property on the RTB?
myRichTextBox.ScrollBars = RichTextBoxScrollBars.None;
Edit: I think I misinterpreted what you needed. Searching around, I found this similar post on another forum: http://www.vbforums.com/showthread.php?793671-RESOLVED-RichTextBox-Visual-Bug
This user is setting the value of an RTB based on a selection in a list view. When a new value is set and does not require a scrollbar it doesn't re-draw and still shows the bar.
It seems like adding myRichTextBox.Clear(); myRichTextBox.Refresh(); should help. In this case that user is also programatically setting the ScrollBars property as well.
Also, are you able to determine how many lines of text can fit in the RichTextBox before a scrollbar is needed? I suppose that might vary based on system settings on the machine, but you might just be able to programatically check myrtb.Scrollbars = (myrtb.Lines.Length > X) ? Vertical : None; (excuse the psuedo code syntax)
What helped for me was just calling the refresh() method twice. Very ugly, but it does the job.
Hmm, after more thorough testing this ugly fix proved to be not so much of a fix afterall. It helps, but still some glitches.
refresh();
update();
seems like a better solution.
I was having this same problem. I solved it by calling the Invalidate() method which forces the control to repaint.
Me.RichTextBox.Clear()
'Call Invalidate in order to force the RichTextBox to repaint. I do this so that any
'Visible Scroll bars are removed after clearing the Text
Me.RichTextBox.Invalidate()
I tried with Refresh(); Update(); Invalidate();,but it didn't worked for me.
I solved this problem using following three lines :-
RitchTextBox.Clear(); //Clearing text in RichTextBox
RitchTextBox.ScrollBars = RichTextBoxScrollBars.None; //Remove scroll
RitchTextBox.ScrollBars = RichTextBoxScrollBars.Vertical; //Again add scroll
Try those above three lines. It will work 100%.

Stopping line jump when refreshing a C# datagrid

We display our data on datagrids, bound to a dataset, which is in turn fed from a Progress database on the server. During processing, we need to make a change to the data-set and refresh it's value from the server. So far, all well and good and no problems.
The problem is that when we come back with the new data, we want the selection in the datagrid to remain on the same row it was on before. We've managed this with the following code:
int iPostingPos = dgridPostings.CurrentRow.Index;
// process data on server
dataContTranMatch.RunBoProcedure(dataContTranMatch.BoProcedure,
transactionMatchingDataSet);
// Reload Data
LoadData();
if (iPostingPos > ttPOSTingsRowBindingSource.Count)
{
iPostingPos = ttPOSTingsRowBindingSource.Count;
}
if (ttPOSTingsRowBindingSource.Count > 0)
{
ttPOSTingsRowBindingSource.Position = iPostingPos;
dgridPostings.Rows[iPostingPos].Selected = true;
}
This works, but we get the selected line jumping about on the screen, which is really annoying the users.
For example, if you select row 7, then run this code, you have row 7 selected, selection then jumps to row 0, then jumps back to row 7. This isn't acceptable.
In an attempt to fix this, we've tried enclosing the above code in the following additional lines:
chTableLayoutPanel1.SuspendLayout();
*DO CODE*
chTableLayoutPanel1.ResumeLayout();
But this didn't help.
So far, the most acceptable solution that we've been able to reach is to change the colour on the selection so that you can't see it, letting it leap about and then putting the colours back as they should be. This makes the flicker more acceptable.
dgridPostings.RowsDefaultCellStyle.SelectionBackColor =
SystemColors.Window;
dgridPostings.RowsDefaultCellStyle.SelectionForeColor =
SystemColors.ControlText;
DO CODE
dgridPostings.RowsDefaultCellStyle.SelectionBackColor =
SystemColors.Highlight;
dgridPostings.RowsDefaultCellStyle.SelectionForeColor =
SystemColors.HighlightText;
We beleive that the issue is caused by the binding source being temporarily empty as the dataset is refreshed, we then re-navigate one it's got data in it again.
Can anyone offer any ideas on how we can prevent this unpleasent flicker from occuring?
Many thanks
Colin
It may be a bit heavy handed but one option would be to suspend painting of the control. A user asked how to achieve this here: How Do I Suspend Painting For a Control and Its' Children. I've used the selected answer there to achieve something similar.

TextBox Scrollbar. Scrolling to end of TextBox within Thread

I've tried all the answers suggest in Stack Overflow to get my scrollbar to move to the bottom as text is being updated, but I have a feeling its not working because it's within a thread. My code is below ...
foreach(HtmlAgilityPack.HtmlNode paginationUser in paginationUsers) {
String userUrl = paginationUser.GetAttributeValue("id","");
this.Invoke((MethodInvoker)delegate {
txtLog.AppendText("...... Added " + userUrl + Environment.NewLine);
txtLog.Select(txtLog.Text.Length, 0);
txtLog.ScrollToCaret();
});
}
Is it the thread thats causing the code not to work? And what's a better solution?
Try to add this code :
TextBox.SelectionStart = txtLogEntries.Text.Length;
TextBox.ScrollToCaret();
at onTextChanged TextBox event .
I feel using this code is better:
TextBox.AppendText("your text")
it will automatically scroll to the end of the newly appended text & the auto scrolling animation seems more smoother compared to TextBox.ScrollToCaret() method
you can put this code at TextChanged TextBox event
I am having the same problem with WPF, using a thread to write to the textbox. It works fine until I add the ScrollToEnd.
I have no solution, just some remarks.
You are not locking the control. You should if you are filling it from a tread.
If I use Invoke it does work (but the UI becomes unresponsive). I use BeginInvoke, which is smoother but then it totally locks up if I use ScrollToEnd.
It seems to be some kind of triggering issue, one event causing the other.
Try feeding text slowly and see what happens, the worker thread may be flooding the textbox, giving it a really hard time, not allowing the main thread to do its thing.

Categories