Closed memoarfaa closed 3 weeks ago
@memoarfaa just to confirm I understand the issue correctly - is the issue related to to the fact the form remains in focus? If yes - why is it important, and how is it affecting your developer experience?
is the issue related to to the fact the form remains in focus? yes Save time while designing
Looking at your animation, it looks like you're running a custom form with custom properties and behaviours (doing NC-painting?)....
Yes true https://github.com/memoarfaa/SkinFormCore
I just started a new theme library that has been converted from Winforms .Net framework to .net Core but .net Core designer is not responding to any Nc painting until Close and reopen the form every time
I fixed the Nc painting by add SetWindowPos to every property but I still can't get Inactive title bar color because .net Core designer doesn't take care about WM_NCACTIVATE message . any idea.
SetWindowPos(Handle, IntPtr.Zero, 0, 0, 0, 0, (int)(SWPFlags.SWP_NOACTIVATE | SWPFlags.SWP_NOMOVE | SWPFlags.SWP_NOSIZE | SWPFlags.SWP_NOZORDER | SWPFlags.SWP_FRAMECHANGED));
Yes true memoarfaa/SkinFormCore
This looks pretty cool. What license have you put your code under?
MIT License Any suggestion to make it widely used in .Net Core Winforms is Welcome
If you're up for a challenge, we have some long-standing issues with MDI child window rendering - https://github.com/dotnet/winforms/issues/3691. The root issue is within the realms of Windows code, but there's no hope it'll ever be fixed. So an alternative would be to come up with a Windows Forms opt-in functionality (e.g., a renderer of some kind) that would allow rendering NC-area of the MDI child windows to look native. 😉
In short answer issues https://github.com/dotnet/winforms/issues/3691. solved in memoarfaa/SkinFormCore
1- download
SkinFormCore v1
2- Add refence to SkinFramWorkCore.dll
in your project
3- Create new MDI Window
4- Create methods to Show child window
new SkinForm() { MdiParent = this }.Show();
Result is
I'm also attached simple project
I'm waiting the answer about your test result in any operating system 8,8.1,10,11
@lonitra would be super interested in what you're doing with the skinning, thank you for sharing! This is something we will have to investigate in our out of process designer. It might be that the window needs to be invalidated to force it to repaint.
We're tracking that child window in VS on our end. We've also got some dark mode and styling work starting in .NET 9, so I think we can close this.
@merriemcgaw
We're tracking that child window in VS on our end. We've also got some dark mode and styling work starting in .NET 9, so I think we can close this.
This issue was related to the non-client area of ​​the window at design time. In .NET 9, the non-client area has become less stable and more vulnerable not only in design mode but also at runtime. This is due to the new win32 API "DwmSetWindowAttribute" that was introduced internally in .NET 9.
see https://learn.microsoft.com/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute
If I want to test my dark mode at design time eg:
public partial class Form1 : Form
{
public Form1()
{
#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
Application.SetColorMode(SystemColorMode.Dark);
#pragma warning restore WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
InitializeComponent();
}
}
https://github.com/user-attachments/assets/1aaf9110-218f-43d0-9dc4-7a8cfb784fc9
1- VS Designer look bad in dark mode at least the the non-client area Back Color need to be changed.
all custom non-client area painting not working Correctly in dark mode at runtime !. (I will open an issue if required).
why all custom non-client area painting not working Correctly in dark mode at runtime.
this is because the first issue about new win32 API "DwmSetWindowAttribute" that was introduced internally in .NET 9 is it prevent remove the form theme using "SetWindowTheme" win32 API from being applied in "OnHandleCreated" event
related issue is https://github.com/dotnet/winforms/issues/12014 eg:
public partial class Form1 : Form
{
public Form1()
{
#pragma warning disable WFO5001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
if (Application.ColorMode != SystemColorMode.Dark)
Application.SetColorMode(SystemColorMode.Dark);
#pragma warning restore WFO5001 // Type is for ev
InitializeComponent();
}
private const uint WM_NCUAHDRAWCAPTION = 0x00AE;
private const uint WM_NCUAHDRAWFRAME = 0x00AF;
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
PInvoke.SetWindowTheme((HWND)Handle, "", "");
}
protected override void SetVisibleCore(bool value)
{
base.SetVisibleCore(value);
// PInvoke.SetWindowTheme((HWND)Handle, "", "");
}
protected override void WndProc(ref Message m)
{
switch ((uint)m.Msg)
{
case PInvoke.WM_NCACTIVATE:
case PInvoke.WM_NCPAINT:
base.WndProc(ref m);
OnWmNcPain(ref m);
break;
case WM_NCUAHDRAWCAPTION:
case WM_NCUAHDRAWFRAME:
m.Result = 0;
break;
case PInvoke.WM_NCHITTEST:
OnWmNcHitTest(ref m);
break;
default:
base.WndProc(ref m);
break;
}
}
private void ExcludeClipRect(HDC hdc, RECT rcExclude)
{
PInvoke.ExcludeClipRect(hdc, rcExclude.left, rcExclude.top, rcExclude.right, rcExclude.bottom);
}
private unsafe void OnWmNcPain(ref Message m)
{
HWND hWnd = (HWND)m.HWnd;
HRGN region = HRGN.Null;
HRGN copy = PInvoke.CreateRectRgn(0, 0, 0, 0);
if (PInvoke.CombineRgn(copy, (HRGN)(IntPtr)m.WParam, HRGN.Null, RGN_COMBINE_MODE.RGN_COPY) != GDI_REGION_TYPE.RGN_ERROR)
{
region = copy;
}
else
{
PInvoke.DeleteObject(copy);
}
GET_DCX_FLAGS flags = GET_DCX_FLAGS.DCX_WINDOW | GET_DCX_FLAGS.DCX_CACHE | GET_DCX_FLAGS.DCX_INTERSECTRGN;
if (m.Msg == PInvoke.WM_NCLBUTTONDOWN)
{
flags = GET_DCX_FLAGS.DCX_WINDOW | (GET_DCX_FLAGS)0x00010000;
region = HRGN.Null;
}
HDC hdc = PInvoke.GetDCEx(hWnd, region, flags);
if (((HRGN)m.WParam == (int)GDI_REGION_TYPE.NULLREGION) || hdc.Value == IntPtr.Zero || m.Msg != PInvoke.WM_NCPAINT)
hdc = PInvoke.GetWindowDC(hWnd);
if (hdc.Value != IntPtr.Zero)
{
RECT rcWin = new RECT();
RECT rcClient = new RECT();
PInvoke.GetWindowRect(hWnd, out rcWin);
PInvoke.GetClientRect(hWnd, out rcClient);
PInvoke.MapWindowPoints(HWND.Null, (HWND)m.HWnd, (Point*)&rcWin, 2);
PInvoke.OffsetRect(ref rcClient, -rcWin.left, -rcWin.top);
ExcludeClipRect(hdc, rcClient);
PInvoke.OffsetRect(ref rcWin, -rcWin.left, -rcWin.top);
using Graphics g = Graphics.FromHdc(hdc);
VisualStyleRenderer renderer = new VisualStyleRenderer(VisualStyleElement.CreateElement("Window", 0, 0));
g.Clear(SystemColors.WindowFrame);
RECT rcClose = new RECT(rcWin.Width - 42, 10, rcWin.Width - 10, 28);
int width = rcClose.Width;
renderer.SetParameters(VisualStyleElement.Window.CloseButton.Normal);
renderer.DrawBackground(g, rcClose);
rcClose.left -= width + 2;
rcClose.right -= width + 2;
renderer.SetParameters(VisualStyleElement.Window.MaxButton.Normal);
renderer.DrawBackground(g, rcClose);
rcClose.left -= width + 2;
rcClose.right -= width + 2;
renderer.SetParameters(VisualStyleElement.Window.MinButton.Normal);
renderer.DrawBackground(g, rcClose);
if (Icon is not null && ShowIcon)
{
g.DrawIcon(new Icon(Icon, SystemInformation.SmallIconSize), 10, 10);
}
if (!string.IsNullOrEmpty(Text))
{
TextRenderer.DrawText(g, Text, SystemFonts.CaptionFont, new Rectangle(30, 10, rcWin.Width - 225, 30), Color.White, TextFormatFlags.Left | TextFormatFlags.SingleLine | TextFormatFlags.WordEllipsis | TextFormatFlags.ExternalLeading);
}
PInvoke.ReleaseDC(hWnd, hdc);
}
m.Result = 0;
}
private void OnWmNcHitTest(ref Message m)
{
Point point = default;
point.X = LOWORD(m.LParam.ToInt32());
point.Y = HIWORD(m.LParam.ToInt32());
RECT rcWin = new RECT();
PInvoke.GetWindowRect((HWND)Handle, out rcWin);
int width = rcWin.right - rcWin.left;
point.X -= rcWin.left;
point.Y -= rcWin.top;
RECT rcClose = new RECT(rcWin.Width - 42, 10, rcWin.Width - 10, 28);
int rcCloseWidth = rcClose.Width;
Rectangle closeBtnRect = rcClose;
rcClose.left -= rcCloseWidth + 2;
rcClose.right -= rcCloseWidth + 2;
Rectangle restoreRect = rcClose;
rcClose.left -= rcCloseWidth + 2;
rcClose.right -= rcCloseWidth + 2;
Rectangle minRect = rcClose;
if (IsMdiChild && WindowState == FormWindowState.Minimized)
{
base.WndProc(ref m);
}
else
{
if (closeBtnRect.Contains(point))
{
m.Result = 20; // HTCLOSE;
}
else if (restoreRect.Contains(point))
{
m.Result = 9; // HTMAXBUTTON;
}
else if (minRect.Contains(point))
{
m.Result = 8; //HTMINBUTTON;
}
else
base.WndProc(ref m);
}
}
private static int LOWORD(int i)
{
return (short)(i & 0xFFFF);
}
private static int HIWORD(int i)
{
return (short)(i >> 16);
}
}
all custom non-client area painting not working Correctly in dark mode at runtime !. (I will open an issue if required).
Please do open a separate issue for that. Thanks!
Environment
Microsoft Visual Studio Enterprise 2019 Version 16.11.20
.NET version
.NET Core 3.1 and.NET 5
Did this work in a previous version of Visual Studio and/or previous .NET release?
No
Issue description
designer doesn't take care about window state Activation state of form
Steps to reproduce
open new form in design mode click Properties
.net framwork
Diagnostics
No response