Codename.Windows.Input — 让Silverlight使用右键和滚轮事件更简单[2008-12-12更新]

源代码下载:Codename.Windows.Input v0.9.2

更新:

[2008-12-12]

在Silverlight 2正式版中可以运行。

[2008-7-23]

据一网友反映,鼠标按钮状态在MouseButtonDown和MouseButtonUp事件中实现的不正确,现已更正并添加了一点小功能,谢谢此网友提醒。

 

 众所周知,Silvelight现在不支持右键和滚轮事件,不过可以通过另类途径让Silverlight实现右键和滚轮事件。现在网上有好多关于实现右键和滚轮事件的文章,不过好像都没有将其封装成使用简洁便利的类库。为了方便大家使用,故本人将其封装成使用方便的类库。由于本人能力有限,类库封装的并不完美,如当前版本不支持事件路由等,不过不影响使用。

测试如下:

具体使用如下:

使用MouseEvent类中以下函数即可实现相应的功能。

public   static   bool  AttachMouseButtonDownEvent(System.Windows.UIElement element, System.EventHandler < mousebuttoneventargs >  handler) 
public   static   bool  AttachMouseButtonUpEvent(System.Windows.UIElement element, System.EventHandler < MouseButtonEventArgs >  handler)
public   static   bool  AttachMouseWheelEvent(System.Windows.UIElement element, System.EventHandler < MouseWheelEventArgs >  handler)
public   static   void  DetachMouseButtonDownEvent(System.Windows.UIElement element, System.EventHandler < MouseButtonEventArgs >  handler)
public   static   void  DetachMouseRightButtonUpEvent(System.Windows.UIElement element, System.EventHandler < MouseButtonEventArgs >  handler)
public   static   void  DetachMouseWheelEvent(System.Windows.UIElement element, System.EventHandler < MouseWheelEventArgs >  handler)

 

使用MouseEvent类中以下属性可以直接获得鼠标按钮的状态。

public   static  Codename.Windows.Input.MouseButtonState LeftButton {  get ; }
public   static  Codename.Windows.Input.MouseButtonState MiddleButton {  get ; }
public   static  Codename.Windows.Input.MouseButtonState RightButton {  get ; }
public   static  Codename.Windows.Input.MouseButton ChangedButton {  get ; }
public   static  Codename.Windows.Input.MouseButtonState ButtonState {  get ; }
public   static   bool  PreventContextMenu {  set get ; }

 

 设计类图如下:

 

详细的设计请参考代码和代码中的注释

代码如下:

ExpandedBlockStart.gif ContractedBlock.gif /**/ //
// 作者:宋剑飞
// 网名:Codename
// QQ:247823451
// 邮箱:codename.net@hotmail.com
// 声明:本代码可以无偿使用,如将本代码用于商业用途,必须经本人许可,否则视为侵权。
ExpandedBlockStart.gifContractedBlock.gif
/**/ //

using  System;
using  System.Windows;
using  System.Windows.Input;
using  System.Windows.Browser;
using  System.Collections.Generic;

namespace  Codename.Windows.Input
ExpandedBlockStart.gifContractedBlock.gif
{
ContractedSubBlock.gifExpandedSubBlockStart.gif    
MouseEvent#region MouseEvent

ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
    
/// 为 UIElement 提供鼠标中键、右键和滚轮滚动事件。(要使用鼠标的中键和右键功能,请将 Silverlight 控件的 windowless 属性设为 true)
    
/// </summary>

    public static class MouseEvent
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ContractedSubBlock.gifExpandedSubBlockStart.gif        
UIElementMouseStateDictionary#region UIElementMouseStateDictionary

        
//UIElementMouseState 字典
        
//key 为 UIElement
        
//value 为 UIElementMouseState
        private static Dictionary<UIElement, UIElementMouseState> _uiElementMouseStateDictionary;
        
private static Dictionary<UIElement, UIElementMouseState> UIElementMouseStateDictionary
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//该字典用单件模式实现,按需实例化该字典
                if (_uiElementMouseStateDictionary == null && HtmlPage.IsEnabled)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    _uiElementMouseStateDictionary 
= new Dictionary<UIElement, UIElementMouseState>();
                }

                
return _uiElementMouseStateDictionary;
            }

        }


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
DomMouseButtonEvent#region DomMouseButtonEvent
        
        
//该字段用于表明 DomMouseEvent 是否已注册
        static bool _isRegister;
        
private static void _registerDomMouseButtonEvent()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//确保 DomMouseEvent 只被注册一次
            if (!_isRegister)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//注册 HtmlObject 对象的 onmousedown 事件
                HtmlPage.Plugin.AttachEvent("onmousedown", _handleMouseButtonDown);

                
//注册 HtmlObject 对象的 onmouseup 事件
                HtmlPage.Plugin.AttachEvent("onmouseup", _handleMouseButtonUp);

                
//注册 HtmlObject 对象的 oncontextmenu 事件
                _isRegister = HtmlPage.Plugin.AttachEvent("oncontextmenu", _handleContextMenu);
            }

        }


        
//onmousedown 事件的处理函数
        private static void _handleMouseButtonDown(object sender, HtmlEventArgs args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//更新鼠标按钮的状态
            _updateButtonsState(args.MouseButton, MouseButtonState.Pressed);

            
//触发 MouseButtonDown 事件
            _raiseMouseButtonDownEvent();
        }


        
//onmouseup 事件的处理函数
        private static void _handleMouseButtonUp(object sender, HtmlEventArgs args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//更新鼠标按钮的状态
            _updateButtonsState(args.MouseButton, MouseButtonState.Released);

            
//触发 MouseButtonUp 事件
            _raiseMouseButtonUpEvent();
        }


        
//oncontextmenu 事件的处理函数
        private static void _handleContextMenu(object sender, HtmlEventArgs args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (_preventContextMenu)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{ args.PreventDefault(); }
        }


ContractedSubBlock.gifExpandedSubBlockStart.gif        
PreventContextMenu#region PreventContextMenu
        
private static bool _preventContextMenu = true;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获得或设置一个值,该值用来指示是否禁止默认的右键配置菜单显示(默认为禁止)。
        
/// </summary>
        
/// <returns>如果返回为 true ,则表示禁止默认的右键配置菜单显示,否则显示默认的配置菜单。</returns>

        public static bool PreventContextMenu
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return _preventContextMenu; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set { _preventContextMenu = value; }
        }

        
#endregion


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
MouseButtonState#region MouseButtonState

ContractedSubBlock.gifExpandedSubBlockStart.gif        
LeftButton#region LeftButton
        
static MouseButtonState _leftButton;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取鼠标左键的当前状态。
        
/// </summary>
        
/// <returns>鼠标左键的当前状态,为 MouseButtonState.Pressed 或 MouseButtonState.Released。 没有默认值。</returns>

        public static MouseButtonState LeftButton
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return _leftButton; }
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
MiddleButton#region MiddleButton
        
static MouseButtonState _middleButton;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取鼠标中键的当前状态。
        
/// </summary>
        
/// <returns>鼠标中键的当前状态,为 MouseButtonState.Pressed 或 MouseButtonState.Released。没有默认值。</returns>

        public static MouseButtonState MiddleButton
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return _middleButton; }
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
RightButton#region RightButton
        
static MouseButtonState _rightButton;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取鼠标右键的当前状态。
        
/// </summary>
        
/// <returns>鼠标右键的当前状态,为 MouseButtonState.Pressed 或 MouseButtonState.Released。 没有默认值。</returns>

        public static MouseButtonState RightButton
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return _rightButton; }
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
ButtonState#region ButtonState
        
static MouseButtonState _buttonState;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取改变的按钮的状态。
        
/// </summary>
        
/// <returns>改变的按钮的状态。</returns>

        public static MouseButtonState ButtonState
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return _buttonState; }
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
ChangedButton#region ChangedButton
        
static MouseButton _changedButton;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取改变状态的按钮。
        
/// </summary>
        
/// <returns>改变状态的按钮。</returns>

        public static MouseButton ChangedButton
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return _changedButton; }
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
_updateButtonsState#region _updateButtonsState

        
//保存所有已按下的鼠标按钮
        private static MouseButtons _mouseDownButtons;

        
//更新鼠标按钮当前的状态
        private static void _updateButtonsState(MouseButtons buttons, MouseButtonState state)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            MouseButtons changedBtn 
= MouseButtons.None;

            
switch (state)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
case MouseButtonState.Pressed:
                    
//当有鼠标按钮按下时

                    
//用异或求出改变的按键
                    changedBtn = (MouseButtons)(_mouseDownButtons ^ buttons);
                    
//buttons 为当前所有已按下的按钮,直接赋值
                    _mouseDownButtons = buttons;
                    
break;
                
case MouseButtonState.Released:
                    
//当有鼠标按钮释放时

                    
//buttons 为当前释放的按钮,直接赋值
                    changedBtn = buttons;
                    
//buttons 求反,然后再跟 _mouseDownButtons 相与,得到的值才为当前所有已按下的按钮
                    _mouseDownButtons &= (~buttons);
                    
break;
            }


            
//更新属性 ChangedButton
            switch (changedBtn)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
case MouseButtons.Left:
                    _changedButton 
= MouseButton.Left;
                    
break;
                
case MouseButtons.Middle:
                    _changedButton 
= MouseButton.Middle;
                    
break;
                
case MouseButtons.Right:
                    _changedButton 
= MouseButton.Right;
                    
break;
            }


            
//更新属性 LeftButton,MiddleButton,RightButton
            _leftButton = MouseButtonState.Released;
            _middleButton 
= MouseButtonState.Released;
            _rightButton 
= MouseButtonState.Released;

            
if ((_mouseDownButtons & MouseButtons.Left) > 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _leftButton 
= MouseButtonState.Pressed;
            }


            
if ((_mouseDownButtons & MouseButtons.Middle) > 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _middleButton 
= MouseButtonState.Pressed;
            }


            
if ((_mouseDownButtons & MouseButtons.Right) > 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                _rightButton 
= MouseButtonState.Pressed;
            }


            
//更新属性 ButtonState
            _buttonState = state;
        }

        
#endregion


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
MouseButtonDownEvent#region MouseButtonDownEvent

ContractedSubBlock.gifExpandedSubBlockStart.gif        
MouseButtonDownEventDictionary#region MouseButtonDownEventDictionary
        
//MouseButtonDownEvent 字典
        
//key 为 UIElementMouseState
        
//value 为 EventHandler<MouseButtonEventArgs>
        private static Dictionary<UIElementMouseState, EventHandler<MouseButtonEventArgs>> _mouseButtonDownEventDictionary;
        
private static Dictionary<UIElementMouseState, EventHandler<MouseButtonEventArgs>> MouseButtonDownEventDictionary
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//该字典用单件模式实现,按需实例化该字典
                if (_mouseButtonDownEventDictionary == null && HtmlPage.IsEnabled)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    _mouseButtonDownEventDictionary 
= new Dictionary<UIElementMouseState, EventHandler<MouseButtonEventArgs>>();

                    
//必须调用该函数,否则点击右键时会显示默认的配置菜单
                    _registerDomMouseButtonEvent();
                }

                
return _mouseButtonDownEventDictionary;
            }

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
_raiseMouseButtonDownEvent#region _raiseMouseButtonDownEvent
        
//触发 MouseButtonDown 事件
        private static void _raiseMouseButtonDownEvent()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//当 MouseButtonDown 事件被注册过时
            if (_mouseButtonDownEventDictionary != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//循环处理 UIElementMouseStateDictionary 中的所有的 UIElementMouseState 对象
                foreach (UIElementMouseState state in UIElementMouseStateDictionary.Values)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//判断 UIElementMouseState 对象是否有焦点,且在 MouseButtonDownEventDictionary 注册过事件
                    if (state.UIElementMouseEventArgs != null && MouseButtonDownEventDictionary.ContainsKey(state))
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
{
                        
//创建一个新的 MouseButtonEventArgs 对象
                        MouseButtonEventArgs eventArgs = new MouseButtonEventArgs(state);

                        
//触发该事件
                        MouseButtonDownEventDictionary[state](state.UIElement, eventArgs);
                    }

                }

            }

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
AttachMouseButtonDownEvent#region AttachMouseButtonDownEvent
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 添加 (element)UIElement 的 MouseButtonDown 事件处理函数(当该函数调用成功时,默认的右键配置菜单将被屏蔽)。
        
/// </summary>
        
/// <param name="element">触发该事件的元素。</param>
        
/// <param name="handler">要添加的处理该事件的函数。</param>
        
/// <returns>如果添加处理函数成功返回 true ,否则返回 false。</returns>

        public static bool AttachMouseButtonDownEvent(UIElement element, EventHandler<MouseButtonEventArgs> handler)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//当 element 为 null 或 handler 为 null 时,返回 false,没有可添加的委托
            if (element == null || handler == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return false;
            }


            UIElementMouseState uiElementMouseState;

            
//从 UIElementMouseStateDictionary 中获取 uiElementMouseState(UIElementMouseState) 对象
            if (UIElementMouseStateDictionary.TryGetValue(element, out uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//如果可以获得,则说明其他事件已添加此条目

                
//判断 MouseButtonDownEventDictionary 中是否含有键 uiElementMouseState(UIElementMouseState)
                
//注意:必须使用函数 ContainsKey ,不能使用函数 TryGetValue,使用后者会导致当事件添加两个或两个以上事件处理函数时,无法添加事件处理函数
                if (MouseButtonDownEventDictionary.ContainsKey(uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//如果有,则说明该事件已经被注册过,只需在该委托上直接附加
                    MouseButtonDownEventDictionary[uiElementMouseState] += handler;
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//如果没有,则说明该事件是第一次注册,需在 MouseButtonDownEventDictionary 中添加相关条目
                    MouseButtonDownEventDictionary.Add(uiElementMouseState, handler);
                }

            }

            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//如果获取不到,则需添加相关条目

                uiElementMouseState 
= new UIElementMouseState(element);

                
//在 UIElementMouseStateDictionary 中添加相关条目
                UIElementMouseStateDictionary.Add(element, uiElementMouseState);

                
//在 MouseButtonDownEventDictionary 中添加相关条目
                MouseButtonDownEventDictionary.Add(uiElementMouseState, handler);
            }

            
return true;
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
DetachMouseButtonDownEvent#region DetachMouseButtonDownEvent
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 移除 (element)UIElement 的 MouseButtonDown 事件处理函数。
        
/// </summary>
        
/// <param name="element">触发该事件的元素。</param>
        
/// <param name="handler">要移除的处理该事件的函数。</param>

        public static void DetachMouseButtonDownEvent(UIElement element, EventHandler<MouseButtonEventArgs> handler)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//当 element 为 null 或 handler 为 null 或 _mouseButtonDownEventDictionary 为 null 时,直接返回函数,没有可删除的委托
            if (element == null || handler == null || _mouseButtonDownEventDictionary == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }


            UIElementMouseState uiElementMouseState;

            
//当 UIElementMouseStateDictionary 中无法获得 uiElementMouseState(UIElementMouseState) 时,直接返回函数
            
//说明还没有添加过跟 element(UIElement) 相关联的任何事件
            if (!UIElementMouseStateDictionary.TryGetValue(element, out uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }


            
//当 MouseButtonDownEventDictionary 中不含有键 uiElementMouseState(UIElementMouseState) 时,直接返回函数
            
//说明还没有添加过跟 element(UIElement) 相关联的 MouseButtonDown 事件
            
//注意:必须使用函数 ContainsKey ,不能使用函数 TryGetValue,使用后者会导致当事件跟两个或两个以上事件处理函数相关联时,无法移除事件处理函数
            if (!MouseButtonDownEventDictionary.ContainsKey(uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }


            
//在事件中删除委托并判断是否为 null
            
//当事件为 null 时说明已不需该事件,可以从 MouseButtonDownEventDictionary 中移除
            if ((MouseButtonDownEventDictionary[uiElementMouseState] -= handler) == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//从 MouseButtonDownEventDictionary 中移除该事件
                MouseButtonDownEventDictionary.Remove(uiElementMouseState);

                
//判断其它事件是否还包含跟 element(UIElement) 相关联的委托
                if (!MouseButtonUpEventDictionary.ContainsKey(uiElementMouseState) && !MouseWheelEventDictionary.ContainsKey(uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//如果没有,则说明已经没有任何事件跟 element(UIElement) 相关联
                    
//可以从 UIElementMouseStateDictionary 中移除
                    UIElementMouseStateDictionary.Remove(element);
                }

            }

        }


        
#endregion


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
MouseButtonUpEvent#region MouseButtonUpEvent

ContractedSubBlock.gifExpandedSubBlockStart.gif        
MouseButtonUpEventDictionary#region MouseButtonUpEventDictionary
        
//MouseButtonUpEvent 字典
        
//key 为 UIElementMouseState
        
//value 为 EventHandler<MouseButtonEventArgs>
        private static Dictionary<UIElementMouseState, EventHandler<MouseButtonEventArgs>> _mouseButtonUpEventDictionary;
        
private static Dictionary<UIElementMouseState, EventHandler<MouseButtonEventArgs>> MouseButtonUpEventDictionary
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//该字典用单件模式实现,按需实例化该字典
                if (_mouseButtonUpEventDictionary == null && HtmlPage.IsEnabled)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    _mouseButtonUpEventDictionary 
= new Dictionary<UIElementMouseState, EventHandler<MouseButtonEventArgs>>();
                    
//必须调用该函数,否则点击右键时会显示默认的配置菜单
                    _registerDomMouseButtonEvent();
                }

                
return _mouseButtonUpEventDictionary;
            }

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
_raiseMouseButtonUpEvent#region _raiseMouseButtonUpEvent
        
//触发 MouseButtonUp 事件
        private static void _raiseMouseButtonUpEvent()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//当 MouseButtonUp 事件被注册过时
            if (_mouseButtonUpEventDictionary != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//循环处理 UIElementMouseStateDictionary 中的所有的 UIElementMouseState 对象
                foreach (UIElementMouseState state in UIElementMouseStateDictionary.Values)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//判断 UIElementMouseState 对象是否有焦点,且在 MouseButtonDownEventDictionary 注册过事件
                    if (state.UIElementMouseEventArgs != null && MouseButtonUpEventDictionary.ContainsKey(state))
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
{
                        
//创建一个新的 MouseButtonEventArgs 对象
                        MouseButtonEventArgs eventArgs = new MouseButtonEventArgs(state);

                        
//触发该事件
                        MouseButtonUpEventDictionary[state](state.UIElement, eventArgs);
                    }

                }

            }

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
AttachMouseButtonUpEvent#region AttachMouseButtonUpEvent

ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 添加 (element)UIElement 的 MouseButtonUp 事件处理函数(当该函数调用成功时,默认的右键配置菜单将被屏蔽)。
        
/// </summary>
        
/// <param name="element">触发该事件的元素。</param>
        
/// <param name="handler">要添加的处理该事件的函数。</param>
        
/// <returns>如果添加处理函数成功返回 true ,否则返回 false。</returns>

        public static bool AttachMouseButtonUpEvent(UIElement element, EventHandler<MouseButtonEventArgs> handler)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//当 element 为 null 或 handler 为 null 时,返回 false,没有可添加的委托
            if (element == null || handler == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return false;
            }


            UIElementMouseState uiElementMouseState;

            
//从 UIElementMouseStateDictionary 中获取 uiElementMouseState(UIElementMouseState) 对象
            if (UIElementMouseStateDictionary.TryGetValue(element, out uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//如果可以获得,则说明其他事件已添加此条目

                
//判断 MouseButtonUpEventDictionary 中是否含有键 uiElementMouseState(UIElementMouseState)
                
//注意:必须使用函数 ContainsKey ,不能使用函数 TryGetValue,使用后者会导致当事件添加两个或两个以上事件处理函数时,无法添加事件处理函数
                if (MouseButtonUpEventDictionary.ContainsKey(uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//如果有,则说明该事件已经被注册过,只需在该委托上直接附加
                    MouseButtonUpEventDictionary[uiElementMouseState] += handler;
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//如果没有,则说明该事件是第一次注册,需在 MouseButtonUpEventDictionary 中添加相关条目
                    MouseButtonUpEventDictionary.Add(uiElementMouseState, handler);
                }

            }

            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//如果获取不到,则需添加相关条目

                uiElementMouseState 
= new UIElementMouseState(element);

                
//在 UIElementMouseStateDictionary 中添加相关条目
                UIElementMouseStateDictionary.Add(element, uiElementMouseState);

                
//在 MouseButtonUpEventDictionary 中添加相关条目
                MouseButtonUpEventDictionary.Add(uiElementMouseState, handler);
            }

            
return true;
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
DetachMouseRightButtonUpEvent#region DetachMouseRightButtonUpEvent
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 移除 (element)UIElement 的 MouseButtonUp 事件处理函数。
        
/// </summary>
        
/// <param name="element">触发该事件的元素。</param>
        
/// <param name="handler">要移除的处理该事件的函数。</param>

        public static void DetachMouseRightButtonUpEvent(UIElement element, EventHandler<MouseButtonEventArgs> handler)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//当 element 为 null 或 handler 为 null 或 _mouseButtonUpEventDictionary 为 null 时,直接返回函数,没有可删除的委托
            if (element == null || handler == null || _mouseButtonUpEventDictionary == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }


            UIElementMouseState uiElementMouseState;

            
//当 UIElementMouseStateDictionary 中无法获得 uiElementMouseState(UIElementMouseState) 时,直接返回函数
            
//说明还没有添加过跟 element(UIElement) 相关联的任何事件
            if (!UIElementMouseStateDictionary.TryGetValue(element, out uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }


            
//当 MouseButtonUpEventDictionary 中不含有键 uiElementMouseState(UIElementMouseState) 时,直接返回函数
            
//说明还没有添加过跟 element(UIElement) 相关联的 MouseButtonUp 事件
            
//注意:必须使用函数 ContainsKey ,不能使用函数 TryGetValue,使用后者会导致当事件跟两个或两个以上事件处理函数相关联时,无法移除事件处理函数
            if (!MouseButtonUpEventDictionary.ContainsKey(uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }


            
//在事件中删除委托并判断是否为 null
            
//当事件为 null 时说明已不需该事件,可以从 MouseButtonUpEventDictionary 中移除
            if ((MouseButtonUpEventDictionary[uiElementMouseState] -= handler) == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//从 MouseButtonUpEventDictionary 中移除该事件
                MouseButtonUpEventDictionary.Remove(uiElementMouseState);

                
//判断其它事件是否还包含跟 element(UIElement) 相关联的委托
                if (!MouseButtonDownEventDictionary.ContainsKey(uiElementMouseState) && !MouseWheelEventDictionary.ContainsKey(uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//如果没有,则说明已经没有任何事件跟 element(UIElement) 相关联
                    
//可以从 UIElementMouseStateDictionary 中移除
                    UIElementMouseStateDictionary.Remove(element);
                }

            }

        }


        
#endregion


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
MouseWheelEvent#region MouseWheelEvent

ContractedSubBlock.gifExpandedSubBlockStart.gif        
MouseWheelEventDictionary#region MouseWheelEventDictionary
        
//MouseWheelEvent 字典
        
//key 为 UIElementMouseState
        
//value 为 EventHandler<MouseButtonEventArgs>
        private static Dictionary<UIElementMouseState, EventHandler<MouseWheelEventArgs>> _mouseWheelEventDictionary;
        
private static Dictionary<UIElementMouseState, EventHandler<MouseWheelEventArgs>> MouseWheelEventDictionary
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//该字典用单件模式实现,按需实例化该字典
                if (_mouseWheelEventDictionary == null && HtmlPage.IsEnabled)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    _mouseWheelEventDictionary 
= new Dictionary<UIElementMouseState, EventHandler<MouseWheelEventArgs>>();
                    
//注册 HtmlObject 对象的 onmousewheel 事件
                    HtmlPage.Plugin.AttachEvent("onmousewheel", _handleMouseWheel);
                }

                
return _mouseWheelEventDictionary;
            }

        }


        
//onmousewheel 事件的处理函数
        private static void _handleMouseWheel(object sender, HtmlEventArgs args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
double delta = 0;

            ScriptObject eventObj 
= args.EventObject;

            
if (eventObj.GetProperty("wheelDelta"!= null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                delta 
= ((double)eventObj.GetProperty("wheelDelta")) / 120;

                
if (HtmlPage.Window.GetProperty("opera"!= null)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{ delta = -delta; }
            }

            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (eventObj.GetProperty("detail"!= null)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    delta 
= -((double)eventObj.GetProperty("detail")) / 3;

                    
if (HtmlPage.BrowserInformation.UserAgent.IndexOf("Macintosh"!= -1)
                        delta 
= delta * 3;
                }

            }


            
if (delta != 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                MouseWheelEventArgs wheelArgs 
= null;

                
foreach (UIElementMouseState state in UIElementMouseStateDictionary.Values)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
if (state.UIElementMouseEventArgs != null && MouseWheelEventDictionary.ContainsKey(state))
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
{
                        
//创建一个新的 MouseWheelEventArgs 对象
                        wheelArgs = new MouseWheelEventArgs(delta, state);

                        
//触发该事件
                        MouseWheelEventDictionary[state](state.UIElement, wheelArgs);

                        
//阻止浏览器响应鼠标滚动事件
                        args.PreventDefault();
                    }

                }


            }

        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
AttachMouseWheelEvent#region AttachMouseWheelEvent
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 添加 (element)UIElement 的 MouseWheel 事件处理函数。
        
/// </summary>
        
/// <param name="element">触发该事件的元素。</param>
        
/// <param name="handler">要添加的处理该事件的函数。</param>
        
/// <returns>如果添加处理函数成功返回 true ,否则返回 false。</returns>

        public static bool AttachMouseWheelEvent(UIElement element, EventHandler<MouseWheelEventArgs> handler)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//当 element 为 null 或 handler 为 null 时,返回 false,没有可添加的委托
            if (element == null || handler == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return false;
            }


            UIElementMouseState uiElementMouseState;

            
//从 UIElementMouseStateDictionary 中获取 uiElementMouseState(UIElementMouseState) 对象
            if (UIElementMouseStateDictionary.TryGetValue(element, out uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//如果可以获得,则说明其他事件已添加此条目

                
//判断 MouseWheelEventDictionary 中是否含有键 uiElementMouseState(UIElementMouseState)
                
//注意:必须使用函数 ContainsKey ,不能使用函数 TryGetValue,使用后者会导致当事件添加两个或两个以上事件处理函数时,无法添加事件处理函数
                if (MouseWheelEventDictionary.ContainsKey(uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//如果有,则说明该事件已经被注册过,只需在该委托上直接附加
                    MouseWheelEventDictionary[uiElementMouseState] += handler;
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//如果没有,则说明该事件是第一次注册,需在 MouseWheelEventDictionary 中添加相关条目
                    MouseWheelEventDictionary.Add(uiElementMouseState, handler);
                }

            }

            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//如果获取不到,则需添加相关条目

                uiElementMouseState 
= new UIElementMouseState(element);

                
//在 UIElementMouseStateDictionary 中添加相关条目
                UIElementMouseStateDictionary.Add(element, uiElementMouseState);

                
//在 MouseWheelEventDictionary 中添加相关条目
                MouseWheelEventDictionary.Add(uiElementMouseState, handler);
            }

            
return true;
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
DetachMouseWheelEvent#region DetachMouseWheelEvent
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 移除 (element)UIElement 的 MouseWheel 事件处理函数。
        
/// </summary>
        
/// <param name="element">触发该事件的元素。</param>
        
/// <param name="handler">要移除的处理该事件的函数。</param>

        public static void DetachMouseWheelEvent(UIElement element, EventHandler<MouseWheelEventArgs> handler)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//当 element 为 null 或 handler 为 null 或 _mouseWheelEventDictionary 为 null 时,直接返回函数,没有可删除的委托
            if (element == null || handler == null || _mouseWheelEventDictionary == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }


            UIElementMouseState uiElementMouseState;

            
//当 UIElementMouseStateDictionary 中无法获得 uiElementMouseState(UIElementMouseState) 时,直接返回函数
            
//说明还没有添加过跟 element(UIElement) 相关联的任何事件
            if (!UIElementMouseStateDictionary.TryGetValue(element, out uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }


            
//当 MouseWheelEventDictionary 中不含有键 uiElementMouseState(UIElementMouseState) 时,直接返回函数
            
//说明还没有添加过跟 element(UIElement) 相关联的 MouseWheel 事件
            
//注意:必须使用函数 ContainsKey ,不能使用函数 TryGetValue,使用后者会导致当事件跟两个或两个以上事件处理函数相关联时,无法移除事件处理函数
            if (!MouseWheelEventDictionary.ContainsKey(uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
return;
            }


            
//在事件中删除委托并判断是否为 null
            
//当事件为 null 时说明已不需该事件,可以从 MouseWheelEventDictionary 中移除
            if ((MouseWheelEventDictionary[uiElementMouseState] -= handler) == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//从 MouseWheelEventDictionary 中移除该事件
                MouseWheelEventDictionary.Remove(uiElementMouseState);

                
//判断其它事件是否还包含跟 element(UIElement) 相关联的委托
                if (!MouseButtonUpEventDictionary.ContainsKey(uiElementMouseState) && !MouseButtonDownEventDictionary.ContainsKey(uiElementMouseState))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//如果没有,则说明已经没有任何事件跟 element(UIElement) 相关联
                    
//可以从 UIElementMouseStateDictionary 中移除
                    UIElementMouseStateDictionary.Remove(element);
                }

            }

        }


        
#endregion


        
#endregion

    }

    
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif    
UIElementMouseState#region UIElementMouseState

    
//该类用于确定 UIElement 是否实现鼠标事件
    internal class UIElementMouseState
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
//该字段用来实现 MouseButtonEventArgs 和 MouseWheelEventArgs 的 GetPosition 函数
        
//同时该字段用来判断该 UIElement 是否可以响应鼠标事件,如果该字段为 null 时,表示不能响应鼠标事件,否则表示可以响应鼠标事件
        internal MouseEventArgs UIElementMouseEventArgs;
        
internal UIElement UIElement;

        
public UIElementMouseState(UIElement element)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            UIElement 
= element;

            UIElement.MouseEnter 
+= new System.Windows.Input.MouseEventHandler(element_MouseEnter);
            UIElement.MouseLeave 
+= new System.Windows.Input.MouseEventHandler(element_MouseLeave);
            UIElement.MouseMove 
+= new System.Windows.Input.MouseEventHandler(element_MouseMove);
        }

        
//处理 UIElement 的 MouseMove 事件
        private void element_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//该 UIElement 可以响应鼠标事件
            UIElementMouseEventArgs = e;
        }

        
//处理 UIElement 的 MouseLeave 事件
        private void element_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//该 UIElement 不能响应鼠标事件
            UIElementMouseEventArgs = null;
        }

        
//处理 UIElement 的 MouseEnter 事件
        private void element_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//该 UIElement 可以响应鼠标事件
            UIElementMouseEventArgs = e;
        }

    }


    
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif    
MouseWheelEventArgs#region MouseWheelEventArgs

ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
    
/// 为报告鼠标设备的鼠标滚轮增量值更改的事件提供数据。
    
/// </summary>

    public class MouseWheelEventArgs : RoutedEventArgs
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        MouseEventArgs mouseEventArgs;

        
internal MouseWheelEventArgs(double delta, UIElementMouseState mouseState)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            mouseEventArgs 
= mouseState.UIElementMouseEventArgs;

            Source 
= mouseState.UIElement;
            Delta 
= delta;
        }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 返回鼠标指针相对于指定元素的位置。
        
/// </summary>
        
/// <param name="relativeTo">在计算鼠标指针位置时用作参考框架的元素。</param>
        
/// <returns>相对于指定对象的鼠标指针位置的 x 和 y 坐标。</returns>

        public Point GetPosition(UIElement relativeTo)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return mouseEventArgs.GetPosition(relativeTo);
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取指示鼠标滚轮变更量的值。
        
/// </summary>
        
/// <returns>鼠标滚轮的变更量。如果鼠标滚轮朝上旋转(背离用户的方向),则该值为正;如果鼠标滚轮朝下旋转(朝着用户的方向),则该值为负。</returns>

        public double Delta
ExpandedSubBlockStart.gifContractedSubBlock.gif        
getprivate set; }

    }


    
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif    
MouseButtonEventArgs#region MouseButtonEventArgs

ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
    
/// 为与鼠标按钮相关的事件提供数据。
    
/// </summary>

    public class MouseButtonEventArgs : RoutedEventArgs
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        MouseEventArgs _mouseEventArgs;

        
internal MouseButtonEventArgs(UIElementMouseState mouseState)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            _mouseEventArgs 
= mouseState.UIElementMouseEventArgs;

            Source 
= mouseState.UIElement;
            Handled 
= true;
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 返回鼠标指针相对于指定元素的位置。
        
/// </summary>
        
/// <param name="relativeTo">在计算鼠标指针位置时用作参考框架的元素。</param>
        
/// <returns>相对于指定对象的鼠标指针位置的 x 和 y 坐标。</returns>

        public Point GetPosition(UIElement relativeTo)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
return _mouseEventArgs.GetPosition(relativeTo);
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取鼠标左键的当前状态。
        
/// </summary>
        
/// <returns>鼠标左键的当前状态,为 MouseButtonState.Pressed 或 MouseButtonState.Released。 没有默认值。</returns>

        public MouseButtonState LeftButton
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return MouseEvent.LeftButton; }
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取鼠标中键的当前状态。
        
/// </summary>
        
/// <returns>鼠标中键的当前状态,为 MouseButtonState.Pressed 或 MouseButtonState.Released。没有默认值。</returns>

        public MouseButtonState MiddleButton
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return MouseEvent.MiddleButton; }
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取鼠标右键的当前状态。
        
/// </summary>
        
/// <returns>鼠标右键的当前状态,为 MouseButtonState.Pressed 或 MouseButtonState.Released。 没有默认值。</returns>

        public MouseButtonState RightButton
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return MouseEvent.RightButton; }
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取改变的按钮的状态。
        
/// </summary>
        
/// <returns>改变的按钮的状态。</returns>

        public MouseButtonState ButtonState
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return MouseEvent.ButtonState; }
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取改变状态的按钮。
        
/// </summary>
        
/// <returns>改变状态的按钮。</returns>

        public MouseButton ChangedButton
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return MouseEvent.ChangedButton; }
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 获取或设置一个值,该值指示路由事件在路由过程中的事件处理当前状态。(该属性当前不可用)
        
/// </summary>

        public bool Handled
ExpandedSubBlockStart.gifContractedSubBlock.gif        
getset; }
    }


    
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif    
MouseButton#region MouseButton

ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
    
/// 定义用于指定鼠标设备上的按钮的值。
    
/// </summary>

    public enum MouseButton
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 鼠标左按钮。
        
/// </summary>

        Left = 1,
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 鼠标中键。
        
/// </summary>

        Middle = 2,
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 鼠标右按钮。
        
/// </summary>

        Right = 4
    }


    
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif    
MouseButtonState#region MouseButtonState

ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
    
/// 指定鼠标按钮的可能状态。
    
/// </summary>

    public enum MouseButtonState
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 该按钮处于释放状态。
        
/// </summary>

        Released,
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 该按钮处于按下状态。
        
/// </summary>

        Pressed
    }


    
#endregion

}

 

声明:本代码可以无偿使用,如将本代码用于商业用途,必须经本人许可,否则视为侵权。

转载于:https://www.cnblogs.com/Codename/archive/2008/07/22/1248308.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值