给WPF程序增加玻璃效果

在Vista中增加了一种Aero新界面,也就是我们所说的玻璃效果,这种效果比较酷,我也常常喜欢在自己写的小程序中加入这种效果。

    

实现这种效果并不难,也就是两个API,MSDN的文章将玻璃框扩展到 WPF 应用程序详细介绍了如何实现这种效果。在google上拿"C# DwmExtendFrameIntoClientArea"做关键字,也能搜到一大把。

我一般是用的CodeProject的文章Adding Glass Effect to WPF using Attached Properties上所述的那样,通过依赖属性注入这种效果,只要在窗口中加一句话src:GlassEffect.IsEnabled="True"即可使能这种效果,用起来非常方便。通过这种方式实现起来的效果如下:

    

看起来一起都非常简单,但这种方法只是仅仅实现了玻璃效果,还有几个不完善的地方:

  1. 这种方法只能实现全屏玻璃效果,不能实现部分玻璃效果。
  2. 实现玻璃效果后,我们往往还需要隐藏标题栏中的图标和文字。
  3. 那些玻璃化的部分不能像标题栏那样通过鼠标拖动窗口。

因此,我将那个代码改动了一下,增加了上述功能,代码如下:  

ExpandedBlockStart.gif 代码
     public   class  GlassInfo: System.Windows.Markup.MarkupExtension
    {
        
public   int  TopMargin {  get set ; }
        
public   bool  ShowIcon {  get set ; }
        
public   bool  ShowTitle {  get set ; }

        
public  GlassInfo()
        {
            TopMargin 
=   - 1 ;
            ShowIcon 
=   true ;
            ShowTitle 
=   true ;
        }

        
public   override   object  ProvideValue(IServiceProvider serviceProvider)
        {
            
return   this ;
        }
    }
    
    
public   class  GlassEffect
    {
        
public   static  GlassInfo GetInfo(DependencyObject obj)
        {
            
return  (GlassInfo)obj.GetValue(InfoProperty);
        }

        
public   static   void  SetInfo(DependencyObject obj, GlassInfo value)
        {
            obj.SetValue(InfoProperty, value);
        }

        
public   static   readonly  DependencyProperty InfoProperty  =
            DependencyProperty.RegisterAttached(
" Info " typeof (GlassInfo),  typeof (GlassEffect),  new  FrameworkPropertyMetadata(OnIsEnabledChanged));


        
public   static   void  OnIsEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            
if  (System.ComponentModel.DesignerProperties.GetIsInDesignMode(obj))
                
return ;
            
            (obj 
as  Window).Loaded  +=  (s, e)  =>  ApplyGlassEffect(obj  as  Window, args.NewValue  as  GlassInfo);

            EnableMouseDrag(obj 
as  Window,(args.NewValue  as  GlassInfo).TopMargin);
        }

        
static   void  ApplyGlassEffect(Window window, GlassInfo info)
        {
            
if  ( ! DwmIsCompositionEnabled())
                
return ;

            var originalBackground 
=  window.Background;
            window.Background 
=  Brushes.Transparent;

            
try
            {
                IntPtr mainWindowPtr 
=   new  WindowInteropHelper(window).Handle;
                HwndSource mainWindowSrc 
=  HwndSource.FromHwnd(mainWindowPtr);
                mainWindowSrc.CompositionTarget.BackgroundColor 
=  Color.FromArgb( 0 0 0 0 );

                var margins 
=  info.TopMargin  ==   - 1   ?   new  MARGINS( - 1 - 1 - 1 - 1 ) :  new  MARGINS { Top  =  info.TopMargin };
                DwmExtendFrameIntoClientArea(mainWindowPtr, 
ref  margins);

                ApplyWindowThemeAttribute(info, mainWindowPtr);
            }
            
catch  (DllNotFoundException)
            {
                window.Background 
=  originalBackground;
            }
        }

        
static   void  ApplyWindowThemeAttribute(GlassInfo info, IntPtr mainWindowPtr)
        {
            WTA_OPTIONS ops 
=   new  WTA_OPTIONS();

            
//  We Want To Hide the Caption and the Icon
            ops.Flags  =  WTNCA_NODRAWCAPTION  |  WTNCA_NODRAWICON  |  WTNCA_NOSYSMENU;

            
//  If we set the Mask to the same value as the Flags, the Flags are Added. If Not They are Removed
             if  ( ! info.ShowTitle)
            {
                ops.Mask 
|=  WTNCA_NODRAWCAPTION;
            }
            
if  ( ! info.ShowIcon)
            {
                ops.Mask 
|=  WTNCA_NODRAWICON  |  WTNCA_NOSYSMENU;
            }

            
//  Set It, The Marshal.Sizeof() stuff is to get the right size of the custom struct, and in UINT/DWORD Form
            SetWindowThemeAttribute(mainWindowPtr, WindowThemeAttributeType.WTA_NONCLIENT,
                
ref  ops, ( uint )Marshal.SizeOf( typeof (WTA_OPTIONS)));
        }

        
#region  设置任意位置拖动效果API
        
const   int  WM_NCLBUTTONDOWN  =   0xA1 ;
        
const   int  HT_CAPTION  =   0x2 ;

        [DllImportAttribute(
" user32.dll " )]
        
static   extern   int  SendMessage(IntPtr hWnd,
                         
int  Msg,  int  wParam,  int  lParam);
        [DllImportAttribute(
" user32.dll " )]
        
static   extern   bool  ReleaseCapture();

        
static   void  EnableMouseDrag(Window window, int  topMargin)
        {
            window.MouseLeftButtonDown 
+=  (s, e)  =>
            {
                var win 
=  s  as  Window;

                var point 
=  e.GetPosition(win);
                
if  (point.Y  >  topMargin)
                    
return ;
            
                Console.WriteLine(e.OriginalSource);
                var mainWindowPtr 
=   new  WindowInteropHelper(win).Handle;
                ReleaseCapture();
                SendMessage(mainWindowPtr, WM_NCLBUTTONDOWN, HT_CAPTION, 
0 );
            };
        }
        
#endregion

        
#region  设置玻璃效果API
        [StructLayout(LayoutKind.Sequential)]
        
struct  MARGINS
        {
            
public   int  Left;
            
public   int  Right;
            
public   int  Top;
            
public   int  Bottom;

            
public  MARGINS( int  left, int  right, int  top, int  bottom)
            {
                
this .Left  =  left;
                
this .Right  =  right;
                
this .Top  =  top;
                
this .Bottom  =  bottom;
            }

            
public  MARGINS(Thickness margin)
            {
                
this .Left  =  ( int )margin.Left;
                
this .Right  =  ( int )margin.Right;
                
this .Top  =  ( int )margin.Top;
                
this .Bottom  =  ( int )margin.Bottom;
            }
        };


        [DllImport(
" DwmApi.dll " )]
        
static   extern   int  DwmExtendFrameIntoClientArea(IntPtr hwnd,  ref  MARGINS pMarInset);

        [DllImport(
" dwmapi.dll " , PreserveSig  =   false )]
        
static   extern   bool  DwmIsCompositionEnabled();

        
public   static   readonly  DependencyProperty IsEnabledProperty  =
            DependencyProperty.RegisterAttached(
" IsEnabled " ,
                
typeof (Boolean),
                
typeof (GlassEffect),
                
new  FrameworkPropertyMetadata(OnIsEnabledChanged)); 
        
#endregion

        
#region  设置标题栏属性

        
///   <summary>
        
///  Do Not Draw The Caption (Text)
        
///   </summary>
         public   static   uint  WTNCA_NODRAWCAPTION  =   0x00000001 ;
        
///   <summary>
        
///  Do Not Draw the Icon
        
///   </summary>
         public   static   uint  WTNCA_NODRAWICON  =   0x00000002 ;
        
///   <summary>
        
///  Do Not Show the System Menu
        
///   </summary>
         public   static   uint  WTNCA_NOSYSMENU  =   0x00000004 ;
        
///   <summary>
        
///  Do Not Mirror the Question mark Symbol
        
///   </summary>
         public   static   uint  WTNCA_NOMIRRORHELP  =   0x00000008 ;

        
///   <summary>
        
///  The Options of What Attributes to Add/Remove
        
///   </summary>
        [StructLayout(LayoutKind.Sequential)]
        
struct  WTA_OPTIONS
        {
            
public   uint  Flags;
            
public   uint  Mask;
        }

        
///   <summary>
        
///  What Type of Attributes? (Only One is Currently Defined)
        
///   </summary>
         enum  WindowThemeAttributeType
        {
            WTA_NONCLIENT 
=   1 ,
        };

        
///   <summary>
        
///  Set The Window's Theme Attributes
        
///   </summary>
        
///   <param name="hWnd"> The Handle to the Window </param>
        
///   <param name="wtype"> What Type of Attributes </param>
        
///   <param name="attributes"> The Attributes to Add/Remove </param>
        
///   <param name="size"> The Size of the Attributes Struct </param>
        
///   <returns> If The Call Was Successful or Not </returns>
        [DllImport( " UxTheme.dll " )]
        
static   extern   int  SetWindowThemeAttribute(IntPtr hWnd, WindowThemeAttributeType wtype,  ref  WTA_OPTIONS attributes,  uint  size); 
        
#endregion

    }

 

使用示例如下:

<Window x:Class="WpfApplication.MainWindow"
    … …

    src:GlassEffect.Info="{util:GlassInfo TopMargin=32, ShowIcon=False, ShowTitle=False}">

最终效果如下:

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值