Windows Forms "System.ArgumentException: Parameter is not valid" from Font.GetHeight(Graphics graphics)

StackOverflow https://stackoverflow.com/questions/15652756

문제

I'm supporting a winforms application using dotnet 3.5 and ComponentFactory Krypton v4.4.0.0, I recently implemented the AppDomain.CurrentDomain.UnhandledException and Application.ThreadException handlers to notify me of exceptions happening on the clients, and found lot of errors showing up in the logs. This one is doing my head in at the moment:

System.ArgumentException: Parameter is not valid.
 at System.Drawing.Font.GetHeight(Graphics graphics)
 at System.Drawing.Font.GetHeight()
 at System.Drawing.Font.get_Height()
 at System.Windows.Forms.Control.set_Font(Font value)
 at System.Windows.Forms.DataGridViewComboBoxEditingControl.ApplyCellStyleToEditingControl(DataGridViewCellStyledataGridViewCellStyle)
 at System.Windows.Forms.DataGridView.BeginEditInternal(Boolean selectAll)
 at System.Windows.Forms.DataGridView.ProcessKeyEventArgs(Message& m)
 at System.Windows.Forms.Control.ProcessKeyMessage(Message& m)
 at System.Windows.Forms.Control.WmKeyChar(Message& m)
 at System.Windows.Forms.Control.WndProc(Message& m)
 at System.Windows.Forms.DataGridView.WndProc(Message& m)
 at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
 at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
 at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam,IntPtr lparam)

Note that the stacktrace is entirely in Windows code. There's another that passes through one of my classes:

System.ArgumentException: Parameter is not valid.
  at System.Drawing.Font.GetHeight(Graphics graphics)
  at System.Drawing.Font.GetHeight()
  at System.Drawing.Font.get_Height()
  at System.Windows.Forms.Control.set_Font(Font value)
  at MyOrg.MyApp.WindowsClient.GuiControls.MaskedTextBoxEditingControl.ApplyCellStyleToEditingControl(DataGridViewCellStyledataGridViewCellStyle)
  at System.Windows.Forms.DataGridView.BeginEditInternal(Boolean selectAll)
  at System.Windows.Forms.DataGridView.ProcessKeyEventArgs(Message& m)
  at System.Windows.Forms.Control.ProcessKeyMessage(Message& m)
  at System.Windows.Forms.Control.WmKeyChar(Message& m)
  at System.Windows.Forms.Control.WndProc(Message& m)
  at System.Windows.Forms.DataGridView.WndProc(Message& m)
  at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
  at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
  at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Here's the code for that snippet:

public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
{
  this.Font = dataGridViewCellStyle.Font;
  this.ForeColor = dataGridViewCellStyle.ForeColor;
  this.BackColor = dataGridViewCellStyle.BackColor;
  this.TextAlign = translateAlignment(dataGridViewCellStyle.Alignment);
}

which doesn't tell me much.

The "System.ArgumentException: Parameter is not valid." error is pretty woeful and gives me very little to go on, but using dotPeek I looked at the code for Font.Get_Height(Graphics g) and discovered it's a GDI+ error, specifically GetFontHeight:

public float GetHeight(Graphics graphics)
{
  if (graphics == null)
  {
    throw new ArgumentNullException("graphics");
  }
  else
  {
    float size;
    int fontHeight = SafeNativeMethods.Gdip.GdipGetFontHeight(new HandleRef((object) this, this.NativeFont), new HandleRef((object) graphics, graphics.NativeGraphics), out size);
    if (fontHeight != 0)
      throw SafeNativeMethods.Gdip.StatusException(fontHeight);
    else
      return size;
  }
}

which is this GDI+ method: http://www.jose.it-berater.org/gdiplus/reference/flatapi/font/gdipgetfontheight.htm

and my status error is Invalidparameter, as documented here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms534175(v=vs.85).aspx

Unfortunately none of this helps me to resolve what's wrong with the Graphics object. This is coming from unhandled exceptions from users in the field. I recently had a memory leak that was caused by a leaking EventHandler and consuming all the available GDI handles, but I've fixed that, so now I'm not sure whether this is a memory leak, a GDI handle leak, or just bad config somewhere that's triggered by users doing something out of the ordinary.

anyone have any ideas? Help much appreciated!

도움이 되었습니까?

해결책 2

I'm using Krypton 4.4 and .NET 4.0 and was experiencing the same behavior, but it dealt with the KryptonComboBox. Like matao, the error appeared to not be passing through my code at all, but rather through the Krypton framework and .NET itself.

After some investigation into the Krypton source code and looking at the stack trace when this error was thrown, I noticed that the KryptonComboBox (or a part of the Krypton framework) was attaching to the Microsoft.Win32.SystemEvents.OnUserPreferenceChanged event which got me thinking. Perhaps the reason this wasn't going through my code was that this event was being triggered from the OS at some point. It still didn't explain why the error was being thrown, but I started thinking about this problem in a different manner.

Now, whenever this error happened, it always traversed through the KryptonComboBox, but it wasn't consistent in any manner. It was actually very difficult to invoke. However, because of the OnUserPreferenceChanged event firing, I started looking at things like Global Policy changes or something that would trigger that event. Through some luck I noticed that if I had my WinForms app running and launched Internet Explorer, I could reliably get this exception to pop up. Don't ask me why this happens, but apparently launching IE somehow fires the OnUserPreferenceChanged event.

Now that I had a reliable way to trigger the exception, I started looking at KryptonComboBox instances in my code and commenting out entire modules to see if I could get this exception to come back. Eventually, I found the error and it turned out to be an error in how code in my WinForms app was being wired up. Specifically, here is the error:

    KryptonComboBox detailView = new KryptonComboBox();
    detailView.Sorted = true;
    detailView.Text = "View";
    detailView.Items.Add(new KryptonListItem("Details", "Detail View"));
    detailView.Items.Add(new KryptonListItem("List", "List"));
    detailView.Items.Add(new KryptonListItem("Tile", "Tiles"));

    ToolStripMenuItem mItem = new ToolStripMenuItem();
    mItem.Tag = detailView;
    mItem.Text = detailView.Text;
    mItem.Click += new EventHandler(contextItem_Click);

My guess is that because detailView is not wired up to the Control pipeline the, the Krypton framework has some issues attempting to update the Palette of the KryptonCombBox control.

One weird nuance that I noticed is that after the first exception was thrown within the Krypton framework, it appeared to corrupt the Graphics object. Subsequent calls to update the Palette (to switch colors of the Krypton controls), the error would always throw but through a different area in the call stack (always initiated from somewhere within my source code).

Matao, I'm not sure this answers your question, but I believe you may have some issue with how you're wiring up your Controls within the DataGridView. Perhaps you're associating a control with the Tag property on something within the DataGridView?

I hope this gives you some insight into your problem.

* Edit *

Per Matao's question, I fixed the problem by removing the code that was adding the KryptonComboBox to the Tag property of the ToolStripMenuItem. Instead, to get the functionality I wanted, I simply added some additional ToolStripMenuItems to the DropDownItems property of mItem.

I would look into your source code for any dynamically created controls that aren't being added to the Control pipeline.

다른 팁

I just ran into this very issue and took me a few hours to figure out, I traced it down to some other part of the codebase getting a reference to a Font from a control, but then performing a Dispose() on that Font. I was able to reproduce this by creating a Windows Form project, adding a TreeView and a DataGridView and executing this on the TreeView

treeView.Font.Dispose();

Hopefully, what I found is helpful for anyone running into this issue.

For me it was because of the Dispose() of DefaultFont

Do not dock DataGrid view to the parent layout

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top