简短版本:
目标: C#中无边界WinForm中的深色,黑暗,Windows 7阴影
已知的现有解决方案1:使用CreateParams的简单XP风格的阴影。
问题:太弱,太轻,太难看。
已知现有解决方案2:使用位图替换表单的GDI。
问题:失去使用控件的功能,只能用作启动画面。
这篇文章的目标:找到这个问题的中位数解决方案或者更好的解决方案。
。 。
长版:
(编辑:我指的是沿着任何窗体边界的阴影,如果不清楚的话。) 我知道有一种方法可以在C#中使用:
制作XP风格的幻影C#Code 1 - 简单的XP风格的阴影(问题:亮,弱,变丑)
// Define the CS_DROPSHADOW constant
private const int CS_DROPSHADOW = 0x00020000;
// Override the CreateParams property
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ClassStyle |= CS_DROPSHADOW;
return cp;
}
}
但是,我试图弄清楚如何使它们看起来像Windows 7中的做(更深和更大的阴影),并且无法找出最佳方法。
我现在创建了一个方法,它可以让我覆盖整个表单GDI,看起来就像一个启动画面(不是我的信用):
C#代码2:用位图替换表单GDI(问题:无法使用表单控件,难以维护GUI)
public void SetBitmap(Bitmap bitmap, byte opacity)
{
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
throw new ApplicationException("The bitmap must be 32ppp with alpha-channel.");
// 1. Create a compatible DC with screen;
// 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC;
// 3. Call the UpdateLayeredWindow.
IntPtr screenDc = Win32.GetDC(IntPtr.Zero);
IntPtr memDc = Win32.CreateCompatibleDC(screenDc);
IntPtr hBitmap = IntPtr.Zero;
IntPtr oldBitmap = IntPtr.Zero;
try
{
hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap
oldBitmap = Win32.SelectObject(memDc, hBitmap);
Win32.Size size = new Win32.Size(bitmap.Width, bitmap.Height);
Win32.Point pointSource = new Win32.Point(0, 0);
Win32.Point topPos = new Win32.Point(Left, Top);
Win32.BLENDFUNCTION blend = new Win32.BLENDFUNCTION();
blend.BlendOp = Win32.AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = opacity;
blend.AlphaFormat = Win32.AC_SRC_ALPHA;
Win32.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA);
}
finally
{
Win32.ReleaseDC(IntPtr.Zero, screenDc);
if (hBitmap != IntPtr.Zero)
{
Win32.SelectObject(memDc, oldBitmap);
Win32.DeleteObject(hBitmap);
}
Win32.DeleteDC(memDc);
}
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00080000; // This form has to have the WS_EX_LAYERED extended style
return cp;
}
}
但是,这确实给了我一个完整的32位背景(因为我需要手动添加这些drophadow),但是我失去了创建可见的表单元素的能力。
所以基本上,我试图找出这两种方法之间的中位数。在不失去其他功能/导致过度重新绘制要求的情况下,会给我深深阴影的东西。
答案 0 :(得分:8)
好的,经过大约4个小时的头脑风暴和编码,我终于开发出了一个解决方案。基本上,我做了2个表格。
表单#1 :通过修改和组合8个图像(4个角渐变+每个方向4个线性渐变)创建阴影,并使用我在上面发布的第二个代码将它们设置为背景(< strong> C#代码2:用位图替换表格GDI )。代码几乎解释了它。
public partial class Dropshadow : Form
{
public Dropshadow(Form parentForm)
{
/*This bit of code makes the form click-through.
So you can click forms that are below it in z-space */
int wl = GetWindowLong(this.Handle, -20);
wl = wl | 0x80000 | 0x20;
SetWindowLong(this.Handle, -20, wl);
InitializeComponent();
//Makes the start location the same as parent.
this.StartPosition = parentForm.StartPosition;
parentForm.Activated += ParentForm_Activated; //Fires on parent activation to do a this.BringToFront()
this.Deactivate += This_Deactivated; //Toggles a boolean that ensures that ParentForm_Activated does fire when clicking through (this)
parentForm.Closed += ParentForm_Closed; //Closes this when parent closes
parentForm.Move += ParentForm_Move; //Follows movement of parent form
//Draws border with standard bitmap modifications and merging
/* Omitted function to avoid extra confusion */
Bitmap getShadow = DrawBlurBorder(parentForm.ClientSize.Width, parentForm.ClientSize.Height);
/* **This code was featured in the original post:** */
SetBitmap(getShadow, 255); //Sets background as 32-bit image with full alpha.
this.Location = Offset; //Set within DrawBlurBorder creates an offset
}
private void ParentForm_Activated(object o, EventArgs e)
{
/* Sets this form on top when parent form is activated.*/
if (isBringingToFront)
{
/*Hopefully prevents recusion*/
isBringingToFront = false;
return;
}
this.BringToFront();
/* Some special tweaks omitted to avoid confusion */
}
private void This_Deactivated(object o, EventArgs e)
{
/* Prevents recusion. */
isBringingToFront = true;
}
/* Closes this when parent form closes. */
private void ParentForm_Closed(object o, EventArgs e)
{
this.Close();
}
/* Adjust position when parent moves. */
private void ParentForm_Move(object o, EventArgs e)
{
if(o is Form)
this.Location = new Point((o as Form).Location.X + Offset.X, (o as Form).Location.Y + Offset.Y);
}
}
表单#2 :这只是在启动时启动了splashhadow表单,我还创建了一些接口,以允许进一步的集成和灵活性,我省略了以避免额外的混淆。基本上确保Dropshadow表单没有从活动表单中删除鼠标的方法,并且如果Dropshadow表单位于顶部,则不会强制用户必须单击两次按钮。
答案 1 :(得分:4)
谢谢,Corylulu。
可行的课程是here。
var f = new Dropshadow(this)
{
BorderRadius = 40,
ShadowColor = Color.Blue
};
f.RefreshShadow();
DrawShadow
创建一个像位图一样的阴影,但还不完美。
这个课程并不完美,但它确实有效。
ShowInTaskBar = false
。
修改强>
我重写了这个类,现在它看起来像是一个真正的DropShadow。
来源是 here 。
你应该知道的一件事是这个班不考虑border-radius
(采取形式css)。
主要属性是
该属性与css box-shadow
相同,请参阅here
这些属性
要求您手动拨打RefreshShadow()
。