实现弹出窗口的功能

2024-07-14

实现弹出窗口的功能(共3篇)

1.实现弹出窗口的功能 篇一

在上一篇《[原创]Silverlight的弹出窗口--展示》中,仅仅是将我制作的基于Silverlight的弹出窗 口作了一个功能性的展示,并提供了一个非常基础的版本的源码,

确实这个版本非常基础,其中存在着众多未经优化的代码,同时结构也存在着一定程度的混乱,因此 如果不从整体上对其进行梳理,仅仅通过阅读代码恐怕是很难了解其整个工作过程的。

此篇的目的就是,从设计的结构上,对弹出窗口这一功能作一个大致的介绍,将贯穿于整个作品的设 计思想描绘出来,而这思想也必然是整作项目中最为稳定的部分,在将来不会产生太大的改动。

源码已经有了小部分的更新,如果上一次有下载的园友,请重新下载

整体结构

首先应当从整体上对这个项目的结构有一个鸟瞰的概念,因此附上架构图一份,当然这并不是正规的 UML图,但应当足以说明不少问题

可以看到,在这个结构中,存在着6个非常重要的组件,他们分别是:

PopupService:核心组件,用于提供弹出窗口的功能,所有弹出窗口都由其进行控制

LayoutMask:位于弹出窗口下部的遮罩层,同时也将提供模态对话框打开时屏蔽下层控件的功能

PopupBox:弹出窗口的基类,与LayoutMask之间具有一定的通信和交互能力,同时提供特效等功能

BoxPage/MessagePage:PopupBox的实现,分别对应不同的功能,但基于此设计,并不存在太多与实现 相关的代码,因此不会作为重点进行讲述

DragService:管理窗口的鼠标拖动功能,从外部引入拖动功能有利于展现与功能的解耦,同时所有与 鼠标拖动相关的实现集中于一个类中,方便了BUG出现之后的定位与修改

PopupService

在我的设计中,我们不能通过直接的新建对象,如BoxPage box = new BoxPage();来生成一个弹出窗 口。

当然最初的设计确实是可以使用new来创建的,但在日后的测试中发现,这样的创建会产生很多问题, 在下面例举一二:

1. 每一个弹出窗口会拥有一个遮罩层,因此后开的弹出窗口一定比之前的在更上层,这就导致先打开 的弹出窗口永远不可能被移到最上方,而在日常操作中,点击后面的窗口应当可以将这个窗口移到最前方

2. 过多的遮罩层导致了资源大量的占用,当打开5个以上弹出窗口时,应用程序的响应将出现明显变 慢的现象

这种种缺陷,都将矛头指向了一处,即我们需要一个统一的环境来管理弹出窗口及其遮罩层,保证多 个弹出窗口所拥有的遮罩层的“单例性”,因此就产生了通过PopupService这样一个“服务”来管理的策 略,其管理方案如下:

1. 一个PopupService对应一个Control,此Control就是弹出窗口的拥有者

2. PopupService会产生一个遮罩层与此Control联系,并且在此后有弹出窗口时都会使用这唯一的一 个遮罩层

3. 无论何时,对于同一个Control,将只会有一个PopupService进行服务

看到上面的方案后,我想大多数人都会发现,PopupService变成了“伪单例”或“局部单例”的类, 因此就着“单例模式”的设计,我们肯定不能简单地通过new的构造来使用这个类,因此就引出了该类的 一个静态方法GetServiceFor,此方法接收一个参数即PopupService的拥有者,当然为了能够将遮罩层铺 在控件上,我们要求控件是一个布局控件,即Panel类型。

为了保证PopupService的伪单例的特性,必须将生成的对象保存起来,这里简单地用到了Dictionary 进行保存,当调用GetServiceFor方法时,首先在缓存池中寻找,如果找不到则调用new进行实例化,随后 放入缓存池中进行持久的保存,以保证日后不会再发生重新构造的问题,其具体代码如下:

public static PopupService GetServiceFor(Panel owner)

{

if (! Cache.ContainsKey(owner))

{

PopupService service = new PopupService (owner);

Cache[owner] = service;

}

return Cache[owner];

}

在这里并没有显式地对Cache对象(Dictionary

类型)进行线程锁,这 是因为Silverlight与Winform类似,所有对UI的操作只能在主线程进行,因此我认为没有必要在一个单线 程执行的环境中进行加锁。

上面讲了PopupService的产生过程,下面例举一下PopupService提供的方法,由于方法十分简单,就 不展开讨论,其方法主要有3个:

1. GetBoxPage:获取在此PopupService管理下的BoxPage的一个对象,有重载

2. GetMessagePage:获取在此PopupService管理下的MessagePage的一个对象,有重载

3. RegisterPopupBox:对已经创建好的但没有纳入PopupService管理的PopupBox对象进行注册,注册 后的对象将由此PopupService进行管理,即分配一个LayoutMask

LayoutMask

LayoutMask听起来就叫“遮罩层”,但其实他不是一个控件,其地位类似于PopupService,是一个“ 管理者”的角色,他将管理多个PopupBox,从而将弹出窗口于PopupService分享开来,起到解耦的作用, 尽可能地减少PopupService的负担,从而使程序结构更加清晰。

而从界面的展现角度来讲,又可以认为LayoutMask确实是一个“控件”,因为他会生成一个Canvas平铺于其所有者(Panel类型)之上,此Canvas就是真正的“遮罩层”,对Canvas设定背景色就会产生模态 对话框的效果,同时所有的弹出窗口都将作为这个Canvas的子元素,通过ZIndex的改变来确定哪一个对话 框处在最前端,从而得以模仿我们日常使用中“点击在后面的窗口之后窗口会被置于最前端”的效果,

LayoutMask提供了与弹出窗口的管理相关的若干方法,其主要对外的方法如下:

1. AddBox:将一个弹出窗口添加进来,当然在调用窗口的Show方法之前,窗口是不会显示出来的, AddBox只是将窗口与本体进行联系。

2. RemoveBox:与AddBox相反,将一个窗口从本容器中除去,此后即使调用窗口的Show方法,窗口也 不会再显示出来了,因此被移除的Box在XAML树中已经是一个孤岛,与XAML根没有联系的元素是不可能被 渲染的。

3. PositionBox:在上一个版本中称为CenterBox,在此版本中加入了新的功能,即连续打开窗口时, 窗口不会叠在一起,而会按一定的偏移量相互错开,因此方法也被改名为PositionBox,其作用就是找到 一个合适的位置来放置弹出窗口。

除了公开的方法之外,其部分内部方法也有着举足轻重的作用:

1. CheckModal:每当AddBox或RemoveBox调用时,都会重新检查是否有弹出窗口是模态的,如果在这 个LayoutMask管理的弹出对话框中有一个或多个是模态的,则需要将作为遮罩层使用的Canvas改为模态以 屏蔽下面的其他控件,其方式是简单地给Canvas加上背景色。

2. MaxZIndex:返回管理的所有弹出对话框的ZIndex中的最大值,这方便了在后层的对话框移到前层 ,只需要设定其ZIndex为MaxZIndex + 1即可。

3. ReorderZIndex:当然ZIndex是有最大值的,一个很熟悉的数字65535,所以如果不断地给窗口增加 ZIndex,必将导致ZIndex超出范围,这当然不是我们所希望的结果。因此就有了一个方法,当ZIndex已经 过大的时候,将所有控件的ZIndex进行重新排列,按照现有的窗口叠放次序,从1开始重新排列ZIndex, 保证ZIndex永远不会超过最大值(当然你硬要连续打开65536个窗口我也真没办法……)

4. RenderMask:当所有弹出窗口关闭时,遮罩层也应该相应消失,而当遮罩层未打开时,也不能打开 新的窗口,所以这里就有一个流程,在第一个窗口打开时需要先将遮罩层打开,因此有了RenderMask方法 ,负责将遮罩层加入到所有者的子元素中并显示出来。

DragService:

DragService是一个辅助类,他将提供窗口的鼠标拖动功能,这个类的结构也非常简单,在构造的时候 将需要窗口的对象传递给他,随后便可通过设定IsDraggable属性来打开/关闭鼠标拖动的功能,对于鼠标 拖动的实现,在网上无论是FLEX,JS,WINFORM还是Silverlight都有很多的实现了,我使用的也与这些大 同小异,主要就是通过监听MouseDown,MouseUp,MouseMove这3个事件来实现,可以看一下IsDraggable 的实现:

public bool IsDraggable

{

get

{

return m_IsDraggable;

}

set

{

if (m_IsDraggable == value)

{

return;

}

if (value)

{

EnableDrag();

}

else

{

DisableDrag ();

}

}

}

当IsDraggable被设定为true时,会调用EnableDrag方法,此方法如下:

private void EnableDrag()

{

PopupBox.DragMouseCaptureArea.MouseLeftButtonDown +=

new MouseButtonEventHandler(Drag_MouseLeftButtonDown);

PopupBox.DragMouseCaptureArea.MouseMove +=

new MouseEventHandler (Drag_MouseMove);

PopupBox.DragMouseCaptureArea.MouseLeftButtonUp +=

new MouseButtonEventHandler(Drag_MouseLeftButtonUp);

}

此方法监听了3个事件,对于拖动的逻辑,是在MouseDown的时候设定“开始拖动”,在MouseMove的时 候,如果已经“开始拖动”,则计算出鼠标移动的距离,使窗口移动同样的距离,最后在MouseUp的时候 “停止拖动”,具体代码可以在源文件中找到,不再浪费此处的空间了~~

而当IsDraggable设为false的时候,则调用DisableDrag方法,方法如下:

private void DisableDrag()

{

PopupBox.DragMouseCaptureArea.MouseLeftButtonDown -= Drag_MouseLeftButtonDown;

PopupBox.DragMouseCaptureArea.MouseMove -= Drag_MouseMove;

PopupBox.DragMouseCaptureArea.MouseLeftButtonUp -= Drag_MouseLeftButtonUp;

}

通过注销3个事件,自然也就停止了拖动的功能。

以后

下一篇将会比较详细地去讲述一下LayoutMask中的一些方法的实现,同时讲述诸如动画效果等复杂内 容的实现,最后介绍如何扩展这个框架来实现自定义的PopupBox。

本文配套源码

2.实现弹出窗口的功能 篇二

在Win10系统上,很多用户依旧习惯使用IE浏览器,但浏览网站时经常遇到一些网站自己弹出窗口,尤其是弹窗广告特别烦人,在Win10下该如何设置IE浏览器来阻止网站弹出窗口呢?

操作方法

1.打开IE浏览器,点击设置按钮,

2.选择Internet选项。

3.转到内容选项卡。

4.勾选启用弹出窗口阻止程序。

5.如果要允许部分网站弹出窗口,可以点击设置进行添加。

6.点击确定,完成操作。

手动设置IE浏览器会稍显麻烦,但更细致一些。如果只想阻止弹窗广告,大家可以使用ADBlock广告过滤大师来完成。

3.实现弹出窗口的功能 篇三

win7旗舰版电脑突然弹出“com surrogate已停止工作”提示窗口怎么办

2.在打开的新窗口中,咱们点击左侧窗格中的高级系统设置,这样就会弹出一个系统属性的窗口了。

3.咱们在弹出来的窗口中,将界面切换到高级这一栏中,然后点击性能后面的按钮。

上一篇:五上期中测试题下一篇:父母之爱的作文七年级精选700字