博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一种用户体验-显示对话框时灰化你的主窗体
阅读量:6303 次
发布时间:2019-06-22

本文共 4211 字,大约阅读时间需要 14 分钟。

袁永福 ( ) 2007-8-10

程序全部源代码下载(工程文件使用VS.NET2003格式):

    在一些Web程序中,有一种页面效果,当弹出一个模拟的对话框时,主页面就整体灰化了,其他的元素不能动弹,只有这个对话框能用,用户关闭了对话框,整个页面才恢复原来的操作.这种用户体验是不错的,提示了用户必须处理的对话框才能继续处理页面.如何实现的我猜想是动态生成一个大的DIV层,把它置于顶层并设置半透明的灰色.

    在WinForm程序中也需要这种用户体验,我们有时观察到主窗体显示了一个对话框,此时用户还试图用鼠标点击主窗体搞些操作,但这种操作注定是要失败,影响到软件可用性.于是我就想到把Web程序中的这种用户体验移植到WinForm程序中来帮助用户意识到主窗体的当前状态.

    实现这个用户体验有两个问题,一是如何知道主窗体弹出对话框,二是如何灰化主窗体.

    首先是解决如何知道主窗体何时弹出对话框,研究了一下,没发现窗体对象System.Windows.Forms.Form类型提供有所帮助的事件方法属性.我们可以在程序代码中,每次弹出对话框前添加灰化主窗体的代码,这样加大了程序开发量,而且代码移植性不好。后来想了又想,试了又试,发现弹出对话框时,主窗体的状态是不可用的,但此时窗体的Enabled属性不能反应这种状态,使用Win32API函数却能正确获得其状态.因此最后决定使用计时器System.Windows.Forms.Timer来不断的调用Win32API函数来测试主窗体是否可用,若可用则不必灰化主窗体,若不可用则灰化主窗体。

    第二步就是灰化主窗体了,根据WEB程序中的实现过程,我们很自然的想到用一个半透明的控件来覆盖整个主窗体,于是我们又如何创造这个半透明控件。纵观System.Windows.Forms名称空间,号称提供半透明效果效果的只有Label类型了,经过测试,发现Label类型的半透明属性是假的,是模拟出来的,它是在控件背景中模拟绘制窗体的背景来搞出半透明的效果,若Label控件背后有其他控件还是要被Label无情的覆盖掉。因此我们需要一个真正的半透明控件,于是我又想了又想,试了又试,找了又找,终于把这个真正的半透明控件搞出来了。

    基础问题解决了,然后就是代码的组成和组件化了,我定义了一个DisableMaskControl控件,实现了真正的半透明处理,里面有个定时器,不断的使用Win32API函数测试这个控件所在的窗体是否有效,若有效则隐藏控件,若无效则显示控件,把控件覆盖整个窗体并置于顶层。这样我就用一百来行的C#代码实现了这种弹出对话框灰化主窗体的用户体验,而且这个代码使用非常简单,只要在需要这种效果的主窗体上添加一行代码 this.Controls.Add( new DisableMaskControl()) 即可。

   此处或许有人提出这个定时器的效率问题,我觉得没多大问题,首先控件少,一个窗体才用一个,相对于高速的CPU,用户手动操作来显示和关闭对话框是极其缓慢的操作。而且定时器中进行的判断不多,只调用了一个API函数,无伤大雅。

   以下是程序的运行效果。

disablemask.PNG

   以下是控件 DisableMaskControl的全部代码。

  1 
using
 System;
  2 
using
 System.Runtime.InteropServices ;
  3 
namespace
 DisableMask
  4 
{
  5 
    
///
 
<summary>
  6 
    
///
 窗体无效时用于掩盖整个状态的半透明控件
  7 
    
///
 
</summary>
  8 
    
///
 
<remarks>
编制 袁永福( 
http://www.xdesigner.cn
 )
</remarks>
  9 
    
public
 
class
 DisableMaskControl : System.Windows.Forms.Control
 10 
    {
 11 
        
///
 
<summary>
 12 
        
///
 初始化对象
 13 
        
///
 
</summary>
 14 
        
public
 DisableMaskControl()
 15 
        {
 16 
            
this
.SetStyle( System.Windows.Forms.ControlStyles.SupportsTransparentBackColor , 
true
 );
 17 
            myTimer 
=
 
new
 System.Windows.Forms.Timer();
 18 
            myTimer.Interval 
=
 
100
 ;
 19 
            myTimer.Tick 
+=
new
 EventHandler(myTimer_Tick);
 20 
            
this
.BackColor 
=
 System.Drawing.Color.FromArgb( 
80
 , 
0
 , 
0
 , 
0
 );
 21 
            myTimer.Start();
 22 
        }
 23 
        
///
 
<summary>
 24 
        
///
 内部用于定时处理的计时器
 25 
        
///
 
</summary>
 26 
        
private
 System.Windows.Forms.Timer myTimer 
=
 
null
;
 27 
 28 
        
///
 
<summary>
 29 
        
///
 已重载:返回控件创建参数
 30 
        
///
 
</summary>
 31 
        
protected
 
override
 System.Windows.Forms.CreateParams CreateParams
 32 
        {
 33 
            
get
 34 
            {
 35 
                System.Windows.Forms.CreateParams ps 
=
 
base
.CreateParams;
 36 
                ps.ExStyle 
=
 ps.ExStyle 
|
 
0x20
 ;
 37 
                
return
 ps ;
 38 
            }
 39 
        }
 40 
 41 
        
///
 
<summary>
 42 
        
///
 绘制控件的背景,啥也不干.
 43 
        
///
 
</summary>
 44 
        
///
 
<param name="pevent">
事件参数
</param>
 45 
        
protected
 
override
 
void
 OnPaintBackground(System.Windows.Forms.PaintEventArgs pevent)
 46 
        {
 47 
        }
 48 
        
///
 
<summary>
 49 
        
///
 绘制控件
 50 
        
///
 
</summary>
 51 
        
///
 
<param name="e">
事件参数
</param>
 52 
        
protected
 
override
 
void
 OnPaint(System.Windows.Forms.PaintEventArgs e)
 53 
        {
 54 
            
using
( System.Drawing.SolidBrush b 
=
 
new
 System.Drawing.SolidBrush( 
this
.BackColor ))
 55 
            {
 56 
                e.Graphics.FillRectangle( b , e.ClipRectangle );
 57 
            }
 58 
        }
 59 
 60 
        
///
 
<summary>
 61 
        
///
 定时器处理
 62 
        
///
 
</summary>
 63 
        
///
 
<param name="sender">
事件参数
</param>
 64 
        
///
 
<param name="e">
事件参数
</param>
 65 
        
private
 
void
 myTimer_Tick(
object
 sender, EventArgs e)
 66 
        {
 67 
            System.Windows.Forms.Form frm 
=
 
this
.FindForm();
 68 
            
if
( frm 
==
 
null
 )
 69 
                
return
 ;
 70 
            
if
( frm.IsDisposed )
 71 
                
return
 ;
 72 
            
if
this
.IsDisposed )
 73 
                
return
 ;
 74 
            
if
this
.IsHandleCreated 
==
 
false
 )
 75 
                
return
 ;
 76 
 77 
            
//
 主窗体显示对话框时窗体不可用,但此时它的Enable属性无法判断其是否真的
 78 
            
//
 不可用,因此必须调用Win32API来判断其是否真的不可用.
 79 
            
if
( IsWindowEnabled( frm.Handle ) 
==
 
false
 )
 80 
            {
 81 
                
if
this
.Visible 
==
 
false
 )
 82 
                {
 83 
                    
this
.Dock 
=
 System.Windows.Forms.DockStyle.None ;
 84 
                    
this
.Bounds 
=
 
new
 System.Drawing.Rectangle( 
 85 
                        
0
 , 
 86 
                        
0
 , 
 87 
                        frm.ClientSize.Width ,
 88 
                        frm.ClientSize.Height );
 89 
                    
this
.BringToFront();    
 90 
                    
this
.Visible 
=
 
true
;
 91 
                    
this
.Refresh();
 92 
                    frm.Refresh();
 93 
                }
 94 
            }
 95 
            
else
 96 
            {
 97 
                
if
this
.Visible )
 98 
                    
this
.Visible 
=
 
false
;
 99 
            }
100 
        }
101 
102 
        
///
 
<summary>
103 
        
///
 用于判断窗体是否有效的Win32API函数
104 
        
///
 
</summary>
105 
        
///
 
<param name="hWnd">
窗体句柄
</param>
106 
        
///
 
<returns>
窗体是否有效
</returns>
107 
        [DllImport(
"
user32.dll
"
, CharSet
=
CharSet.Auto, ExactSpelling
=
true
)]
108 
        
private
 
static
 
extern
 
bool
 IsWindowEnabled(IntPtr hWnd);
109 
110 
    }
//
public class DisableMaskControl : System.Windows.Forms.Control
111 
}

转载地址:http://scfxa.baihongyu.com/

你可能感兴趣的文章
第八章 进程间通信
查看>>
HttpSession接口中的方法(Jsp中的session类的用法)
查看>>
「镁客早报」AI可预测心脏病人死亡时间;机器人开始在美国送外卖
查看>>
MoQ(基于.net3.5,c#3.0的mock框架)简单介绍
查看>>
物联网全面升级,十年内推动工业进入智能化新阶段
查看>>
spring-通过ListFactory注入List
查看>>
一种基于SDR实现的被动GSM嗅探
查看>>
阿里云ECS每天一件事D1:配置SSH
查看>>
SQL Server 性能调优(性能基线)
查看>>
uva 10801 - Lift Hopping(最短路Dijkstra)
查看>>
[Java Web]servlet/filter/listener/interceptor区别与联系
查看>>
POJ 2312Battle City(BFS-priority_queue 或者是建图spfa)
查看>>
从零开始学MVC3——创建项目
查看>>
CentOS 7 巨大变动之 firewalld 取代 iptables
查看>>
延时任务和定时任务
查看>>
linux下的权限问题
查看>>
教你如何使用Flutter和原生App混合开发
查看>>
Spring Boot 整合redis
查看>>
CSS hover改变背景图片过渡动画生硬
查看>>
JDBC(三)数据库连接和数据增删改查
查看>>