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..3ac7fa13b42 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) + { + 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..460ec9eeb99 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 @@ -56,6 +56,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.FontHandle; + + dynamic accessor = bag.TestAccessor.Dynamic; + Assert.NotNull(accessor._fontWrapper); + + bag.Font = secondFont; + Assert.Null(accessor._fontWrapper); + } + [WinFormsTheory] [CommonMemberData(typeof(CommonTestHelper), nameof(CommonTestHelper.GetColorWithEmptyTheoryData))] public void OwnerDrawPropertyBag_ForeColor_Set_GetReturnsExpected(Color value)