如何通过自定义MessageFilter的方式利用按键方式操作控件滚动条[附源代码]如何通过自定义MessageFilter的方式利用按键方式操作控件滚动条[附源代码]
很长一段时间内,一直在做一个SCSF(Smart Client Software Factory)的项目,已经进入UAT阶段。最近,用户提出了一个要求:需要通过按键方式来控制竖直滚动条。具体来讲就
是说,如果一个容器内容过多,用户可以通过按键PageUp和PageDown来控制上下的滚动。刚开始,我试图采用注册事件的方式来实现,但是效果不理想,一来是没有一个单一的地方
来对所有相关空间进行事件注册操作,二来如果容器被子控件完全遮挡,容器空间...
如何通过自定义MessageFilter的方式利用按键方式操作控件滚动条[附源代码]
很长一段时间内,一直在做一个SCSF(Smart Client Software Factory)的项目,已经进入UAT阶段。最近,用户提出了一个要求:需要通过按键方式来控制竖直滚动条。具体来讲就
是说,如果一个容器内容过多,用户可以通过按键PageUp和PageDown来控制上下的滚动。刚开始,我试图采用注册事件的方式来实现,但是效果不理想,一来是没有一个单一的地方
来对所有相关空间进行事件注册操作,二来如果容器被子控件完全遮挡,容器空间的事件将
不会正常出发。有个同事提示采用自定义MessageFilter的方式,我觉得可行,于是进行了
一番尝试。
一、实现原理简介
对于一个Windows Form应用来说,所有事件的触发都是采用消息(Message)的方式来实现的。比如,你点击了一个按钮,Windows会为这个操作之生成一个消息,并将这个消息分发
(Dispatch)给按钮对象。如果能够在消息被分发给目标对象之前,能够对该消息进行了拦
截,那么我们就可以按照我们希望的方式从新生成一个消息,并将其发送给我希望的目标对
象,那么就能过随心所欲地控制目标对象的行为了。而自定义MessageFilter为我们提供了一个最好的消息拦截方式。
就拿我们上面给出控制滚动条的场景来说,当前容器由于内容过多而产生竖直滚动条(假设
子控件的宽度和容器相同),用户键入PageDown按键试图向下滚动。Windows为本次键盘操作生成一个消息,并分发给目标对象(可能并不是我们需要控制的当前容器对象)。在此期间,
我们通过MessageFilter对该消息实施拦截,从新产生一个基于“向下滚动”操作的消息,
并分发给我们需要对其进行控制的容器,那么就实现了对于容器空间滚动条进行控制的目的。
二、实例应用场景简介
熟悉SCSF的朋友应该很清楚,SCSF的通过一个称为Shell的Form作为主界面,利用一个称为Workspace的容器最为整个应用的工作平台。应用动态运行过程中,各个Module的界面采用相同的方式添加到该Workspace之中。下图的就是我们将要演示的例子运行时的截图,为
了简单起见,我直接通过一个System.Windows.Forms.TabControl作为Workspace。主菜单的两个菜单项分别代表两个模块,点击相应的菜单项后,会把相应的界面添加到Workspace中。在这里,我通过System.Windows.Forms.UserControl的方式定义Customer和Order模块的界面,当Customer和Order菜单被点击之后,会动态地在TabControl中添加相应的TabPage,并把相应的UserControl置于其中。由于整个TabControl的高度时固定的,而TabPage中显示的内容则依赖于具体的逻辑,所以对于内容过多的TabPage,将会有一个竖直滚动条。而我们需要通过按键的方式控制的就是当前TabPage的这个滚动条。
下面是该Form相关的代码,静态属性ActiveTabPage代表当前显示的TabPage。UserInfo和OrderInfo是两个UserControl,代表与具体模块相关的界面呈现。
1: using System; 2: using System.Collections.Generic; 3: using
System.Windows.Forms; 4: 5: namespace MessageFilterDemos 6: { 7:
public partial class MainForm : Form 8: { 9: public static TabPage
ActiveTabPage 10: { get;private set; } 11: 12: private
IDictionary
keyedViews 13: { get; set; } 14: 15:
public MainForm() 16: { 17: InitializeComponent(); 18:
this.keyedViews = new Dictionary(); 19: } 20: 21:
protected override void OnLoad(EventArgs e) 22: { 23:
base.OnLoad(e); 24: this.keyedViews.Add("CustomerInfo", new
CustomerInfo()); 25: this.keyedViews.Add("OrderInfo", new
OrderInfo()); 26: } 27: 28: private void Show(string key,
string text, UserControl view) 29: { 30: if
(!this.mainWorkspace.TabPages.ContainsKey(key)) 31: { 32:
this.mainWorkspace.TabPages.Add(key, text); 33:
this.mainWorkspace.TabPages[key].Controls.Add(view); 34:
this.mainWorkspace.TabPages[key].AutoScroll = true; 35: } 36:
this.mainWorkspace.SelectedTab = this.mainWorkspace.TabPages[key]; 37:
ActiveTabPage = this.mainWorkspace.TabPages[key]; 38: } 39: 40:
private void ordeToolStripMenuItem_Click(object sender, EventArgs e) 41:
{ 42: this.Show("OrderInfo", "Order", keyedViews["OrderInfo"]);
43: } 44: 45: private void
customerToolStripMenuItem_Click(object sender, EventArgs e) 46: { 47:
this.Show("CustomerInfo", "Customer", keyedViews["CustomerInfo"]); 48: }
49: 50: private void mainWorkspace_SelectedIndexChanged(object sender,
EventArgs e) 51: { 52: ActiveTabPage =
this.mainWorkspace.SelectedTab; 53: } 54: } 55: }
三、自定义MessageFilter
现在我们进入重点话,如何创建我们需要的自定义MessageFilter,由于我们这个MessageFilter旨在控制TabPag的滚动条,我们将其命名为
ScrollbarControllerMessageFilter。ScrollbarControllerMessageFilter实现了接口System.Windows.Forms.IMessageFilter。下面是IMessageFilter的定义,它仅仅包含一个唯一的成员:PreFilterMessage,对消息的拦截、筛选操作就实现在这里。而Bool类新的返
回值表示是否继续将消息分发的目标对象。
1: public interface IMessageFilter 2: { 3:
[SecurityPermission(SecurityAction.LinkDemand,
Flags=SecurityPermissionFlag.UnmanagedCode)] 4: bool PreFilterMessage(ref
Message m); 5: }
下面是ScrollbarControllerMessageFilter的定义,代码不是很复杂,在这里只需简单的介
绍一下流程:在PreFilterMessage方法中,先判断当前的TabPage是否存在,如果不存在,则不加干涉;然后通过System.Windows.Forms.Message的Msg属性确定当前事件是否是KeyDown,如果不是则直接返回;最后根据System.Windows.Forms.Message的WParam属性判
断当前的按键是否是PageUp或者PageDown,并相应的向目标对象(当前的TabPage)发送一
个关于向上或者向下滚动的消息。消息的发送通过调用Native方法SendMessage实现。
1: using System; 2: using System.Runtime.InteropServices; 3: using System.Windows.Forms; 4: 5: namespace MessageFilterDemos 6: { 7: public class ScrollbarControllerMessageFilter: IMessageFilter 8: { 9: 10: private const int WM_KEYDOWN = 0x100;//Key down 11: private const int WM_VSCROLL = 277; //Scroll 12: private const int SB_PAGEUP = 2; // Scroll Up 13: private const int SB_PAGEDOWN = 3; //Scroll Down 14: 15: #region IMessageFilter Members 16: 17:
[DllImport("user32.dll")] 18: static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam); 19: 20: public bool
PreFilterMessage(ref Message m) 21: { 22: if
(MainForm.ActiveTabPage == null) 23: { 24: return false; 25: } 26: 27: if
(WM_KEYDOWN != m.Msg) 28: { 29: return false; 30: } 31: 32: if (m.WParam.ToInt32() ==
(int)(Keys.PageUp)) 33: { 34:
SendMessage(MainForm.ActiveTabPage.Handle, WM_VSCROLL, SB_PAGEUP, 0); 35: return true; 36: } 37: 38: if (m.WParam.ToInt32() == (int)(Keys.PageDown)) 39: { 40:
SendMessage(MainForm.ActiveTabPage.Handle, WM_VSCROLL, SB_PAGEDOWN, 0); 41: return true; 42: } 43: 44: return false;
45: } 46: 47: #endregion 48: } 49: }
四、注册ScrollbarControllerMessageFilter
对MessageFilter的注册很简单,仅仅需要的是调用System.Windows.Forms.Application
的AddMessageFilter方法即可。实例代码下载地址:
。
1: using System; 2: using System.Windows.Forms; 3: 4: namespace MessageFilterDemos 5: { 6: static class Program 7: { 8: [STAThread] 9: static void Main() 10: { 11: Application.AddMessageFilter(new ScrollbarControllerMessageFilter()); 12: Application.EnableVisualStyles(); 13:
Application.SetCompatibleTextRenderingDefault(false); 14:
Application.Run(new MainForm()); 15: } 16: } 17: }
本文档为【如何通过自定义MessageFilter的方式利用按键方式操作控件滚动条[附源代码]】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。