diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/TreeView/TreeView.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/TreeView/TreeView.cs index 4d6a3c53602..91c61491aee 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/TreeView/TreeView.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/TreeView/TreeView.cs @@ -2782,12 +2782,16 @@ private unsafe void CustomDraw(ref Message m) if (renderinfo is not null && renderinfo.Font is not null) { // Mess with the DC directly... - PInvokeCore.SelectObject(nmtvcd->nmcd.hdc, renderinfo.FontHandle); + Debug.Assert(node._propBag is not null); + if (node._propBag is not null && node._propBag.Font is not null) + { + PInvokeCore.SelectObject(nmtvcd->nmcd.hdc, node._propBag.FontHandle); - // There is a problem in winctl that clips node fonts if the fontSize - // is larger than the treeView font size. The behavior is much better in comctl 5 and above. - m.ResultInternal = (LRESULT)(nint)PInvoke.CDRF_NEWFONT; - return; + // There is a problem in winctl that clips node fonts if the fontSize + // is larger than the treeView font size. The behavior is much better in comctl 5 and above. + m.ResultInternal = (LRESULT)(nint)PInvoke.CDRF_NEWFONT; + return; + } } // fall through and do the default drawing work diff --git a/src/System.Windows.Forms/System/Windows/Forms/OwnerDrawPropertyBag.cs b/src/System.Windows.Forms/System/Windows/Forms/OwnerDrawPropertyBag.cs index a5e39cb6475..c78c4232e50 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/OwnerDrawPropertyBag.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/OwnerDrawPropertyBag.cs @@ -12,6 +12,7 @@ namespace System.Windows.Forms; [Serializable] // This class is participating in resx serialization scenarios for listview/treeview items. public class OwnerDrawPropertyBag : MarshalByRefObject, ISerializable { + private Font? _font; private Control.FontHandleWrapper? _fontWrapper; private static readonly Lock s_internalSyncObject = new(); @@ -38,7 +39,19 @@ internal OwnerDrawPropertyBag() { } - public Font? Font { get; set; } + public Font? Font + { + get => _font; + set + { + if (!ReferenceEquals(_font, value)) + { + _font = value; + _fontWrapper?.Dispose(); + _fontWrapper = null; + } + } + } public Color ForeColor { get; set; } diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/OwnerDrawPropertyBagTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/OwnerDrawPropertyBagTests.cs index b95c33e3378..650d207037c 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/OwnerDrawPropertyBagTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/OwnerDrawPropertyBagTests.cs @@ -4,6 +4,7 @@ #nullable disable using System.Drawing; +using System.Reflection; using System.Runtime.Serialization.Formatters.Binary; using System.Windows.Forms.TestUtilities; @@ -56,6 +57,24 @@ public void OwnerDrawPropertyBag_Font_Set_GetReturnsExpected(Font value) Assert.Equal(value is null, bag.IsEmpty()); } + [WinFormsFact] + public void OwnerDrawPropertyBag_Font_SetDifferentValue_ResetsCachedFontWrapper() + { + using SubTreeView treeView = new(); + OwnerDrawPropertyBag bag = treeView.GetItemRenderStyles(null, 0); + using Font firstFont = new(SystemFonts.MenuFont, FontStyle.Regular); + using Font secondFont = new(SystemFonts.MenuFont, FontStyle.Bold); + + bag.Font = firstFont; + _ = bag.GetType().GetProperty("FontHandle", BindingFlags.Instance | BindingFlags.NonPublic)!.GetValue(bag); + + FieldInfo fontWrapperField = bag.GetType().GetField("_fontWrapper", BindingFlags.Instance | BindingFlags.NonPublic)!; + Assert.NotNull(fontWrapperField.GetValue(bag)); + + bag.Font = secondFont; + Assert.Null(fontWrapperField.GetValue(bag)); + } + [WinFormsTheory] [CommonMemberData(typeof(CommonTestHelper), nameof(CommonTestHelper.GetColorWithEmptyTheoryData))] public void OwnerDrawPropertyBag_ForeColor_Set_GetReturnsExpected(Color value)