Silverlight:使用行为启用滑块上的鼠标滚轮
自定义行为,为 Silverlight 滑块启用鼠标滚轮支持以及更多功能
您可能需要解除对以下路径中某些 DLL 文件的锁定
- MouseWheelApp\MouseWheelApp\Bin\Debug
- MouseWheelApp\MouseWheelBehaviorLibrary\Bin\Debug
在线应用
感谢 Adefwebserver 托管我的应用程序
引言
本文将逐步介绍如何创建两个简单的行为 (behaviors)
,以便为 Silverlight 目前尚不支持的滑块 (Slider)
控件启用鼠标滚轮 (MouseWheel)
功能。本文也将是对行为
的简单介绍。
问题
Silverlight 的 Slider
控件不支持鼠标滚轮
。虽然有一个可以监听的 MouseWheel
事件,但在 Blend 中它不会暴露 Delta
值,该值用于判断滚轮是向上还是向下滚动。为 Slider
添加鼠标支持的一种方法是使用后台代码,但这不如使用行为那样能给设计人员自由,也不具备可重用性。
曾尝试使用 ChangePropertyAction
,但无法获取鼠标值。这限制了设计人员完成工作的能力。
我的解决方案
我制作了两种不同的行为
来启用鼠标滚轮
支持,这些行为
使用在 Slider
上设置的属性以获得一些灵活性。这些属性是:Maximum
、Minimum
、SmallChange
和 Value
。目的是允许设计人员设置边界,以及在滚动鼠标滚轮时值应增加多少。
超越滑块
虽然这是一个针对 Slider
控件的行为
,但它的用途不止于此。因为 Slider
包含了设置 Maximum
、Minimum
和 SmallChange
的属性,所以它非常适合绑定你的属性并设置边界。这最初是为它所关联的任何对象(具有数字属性和边界)提供鼠标滚轮
支持而设计的,因此它也可以通过一些绑定来为其他控件设置鼠标滚轮
功能。它还通过使用行为
避免了后台代码。例如,视频播放器上的音量控制,你可以将音量值绑定到 Slider
的值,并将我的行为关联到视频播放器上,这样用户当鼠标在播放器上方时就可以通过鼠标滚轮
调节音量。或者通过鼠标滚轮
调整图像或窗口的大小,并隐藏滑块
。
基本示例
在深入研究代码之前,我想先概述一下它能做什么,这样你可以决定是否要继续阅读。
在这个我们将在本文中创建的应用里,我们有一个矩形 (rectangle)
和三个滑块 (sliders)
。每个滑块都附加了一个简单的行为
,以启用鼠标滚轮
支持。除此之外,我还将另一个行为
附加到矩形
上,当鼠标在矩形
上时,它将响应鼠标滚轮
事件。这个行为
将改变其中一个滑块
的值。
代码
首先创建一个新的 Silverlight 应用程序,并将其命名为类似 MouseWheelApp
的名称,这个应用将使用这些行为
。然后选择在新网站中托管 Silverlight 应用程序。
现在添加一个新项目,选择 Silverlight 类库,并将其命名为 MouseWheelBehaviorLibrary
。
向 MouseWheelBehaviorLibrary
添加对 System.Windows.Interactivity 的引用。这个 DLL 来自 Microsoft Expression Blend SDK。
在 MouseWheelBehaviorLibrary
项目中,添加一个新类并将其命名为 EnableSliderMouseWheel
。
EnableSliderMouseWheel.cs
- 添加 using 语句
using System.Windows.Interactivity;
- 让类继承自
public class EnableSliderMouseWheel : Behavior<Slider>
该类继承自
Behavior
,并将其泛型设置为Slider
控件。通过将类型设置为Slider
,它将限制此行为
可以附加的对象。对于这个行为
,我想创建一个简单的,它只在附加时或设计人员将其拖放到控件上时启用鼠标滚轮
支持。 - 现在粘贴以下代码
protected override void OnAttached() { base.OnAttached(); //attach event handler on mouse wheel event AssociatedObject.MouseWheel += new MouseWheelEventHandler(SliderMouseScroll_MouseWheel); }
当
行为
“附加”到控件时,这段代码会运行。AssociatedObject
代表它所附加的对象,在我们的例子中是一个Slider
控件。我们正在为MouseWheel
事件添加一个事件处理程序。(此时代码会报错,我稍后会展示SliderMouseScroll_MouseWheel
方法。)基本上,一旦行为
附加到滑块
上,它就会添加事件处理程序来操纵滑块
的值。 - 再次粘贴以下代码
protected override void OnDetaching() { base.OnDetaching(); //remove event handler on mouse wheel event AssociatedObject.MouseWheel -= new MouseWheelEventHandler(SliderMouseScroll_MouseWheel); }
这与上面的代码相反,当它被分离时,它会移除它附加的事件处理程序。
- 现在粘贴行为的核心部分,即鼠标滚动时触发的方法。
void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e) { //Delta = how much the wheel was scrolled. + for up - for down //check to see if Delta is positive. if (e.Delta > 0) { //using small change of Target(slider) property. //this allows how much value can change from the designer // //alternatively you can actually use the delta value instead //of forcing small change increments. AssociatedObject.Value = AssociatedObject.Value + AssociatedObject.SmallChange; } else //same as above just backwards { //using small change of Target(slider) property. //this allows how much value can change from the designer // //alternatively you can actually use the delta value instead //of forcing small change increments. AssociatedObject.Value = AssociatedObject.Value - AssociatedObject.SmallChange; } }
首先我检查 Delta
值,它表示鼠标
滚动的距离和方向。如果是正数,则表示向上滚动,负数则表示向下滚动。我只用 Delta
来检查方向。接下来我获取滑块
的值,并加上或减去滑块
的 SmallChange
值。通过使用 SmallChange
,我允许设计人员设置它应该改变多少。
我没有任何检查来判断它是否会超过或低于边界,这是因为它已经内置了这些检查。
我们的第一个行为完成了。现在我们将开始制作上面展示的示例。
使用行为的应用
下一步是设置一个将使用此行为的应用程序。
- 添加引用到上一步生成的 DLL 或
MouseWheelBehaviorLibrary
。只需转到MouseWheelBehaviorLibrary
项目的 bin 目录并选择MouseWheelBehaviorLibrary
.dll
。 - 在
Blend
中打开MouseWheelApp
的 MainPage.xaml。(右键单击并选择“在 Expression Blend 中打开”)确保我们已经有了这个
行为
。 - 重新创建一个类似这样的界面(矩形、3 个滑块、用作标签的文本块)。确保
矩形
的值没有设置为Auto
,否则将不允许在下一步中进行绑定。滑块和标签位于一个网格中。 - 将
Slider
的值绑定到Rectangle
的属性。确保是双向 (two-way)
绑定。接下来,将Maximum
、Minimum
和SmallChange
设置为适合你项目的值。注意Opacity
的Maximum
应该为 1。 - 将我们创建的
行为
附加到滑块
上并运行。现在,当你在滑块
上滚动鼠标时,它会改变值。(只需将行为
拖放到滑块
上即可。)
更灵活的行为
下一个行为更进一步。它可以附加到任何控件,并且当鼠标在附加的控件上时,它将响应鼠标滚轮
。如前所述,这可以用于为其他控件添加鼠标滚轮
支持。(因为它与前一个几乎相同,我将简要地介绍一些已解释过的细节。)
- 和之前的
行为
一样,我们需要在库中创建一个新类。添加一个名为 EnableMouseWheel.cs 的新类。添加using
using System.Windows.Interactivity;
- 继承自
TargetedTriggerAction<slider><T>
,为T
使用Slider
。同时实现Invoke
方法或复制该方法。public class EnableMouseWheel : TargetedTriggerAction<Slider> { //this method is required for the base class protected override void Invoke(object parameter) { } }
这里的
Invoke
方法我们什么都不做。这种类型的行为
可以附加到任何东西上,而泛型
<T> 可以让你指定一个目标类。Target
用于访问另一个控件。对于我们的例子,我们将其设置为Slider
,这样当鼠标滚轮
滚动时,行为
将改变目标
“Slider
”的值。 - 复制以下代码
protected override void OnAttached() { base.OnAttached(); //add event handler to mouse wheel event ((FrameworkElement)AssociatedObject).MouseWheel += new MouseWheelEventHandler(SliderMouseScroll_MouseWheel); } protected override void OnDetaching() { base.OnDetaching(); //remove the event handler ((FrameworkElement)AssociatedObject).MouseWheel -= new MouseWheelEventHandler(SliderMouseScroll_MouseWheel); } //this method runs on Mouse Wheel event void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e) { //Delta = how much the wheel was scrolled. + for up - for down //check to see if Delta is positive. if (e.Delta > 0) { //using small change of Target(slider) property. //this allows how much value can change from the designer // //alternatively you can actually use the delta value instead //of forcing small change increments. Target.Value = Target.Value + Target.SmallChange; } else //same as above just backwards { //using small change of Target(slider) property. //this allows how much value can change from the designer // //alternatively you can actually use the delta value instead //of forcing small change increments. Target.Value = Target.Value - Target.SmallChange; } }
这基本上是相同的代码,但有一些改动。当我们附加时,我们会将其转换为
FrameworkElement
,它是所有控件的基类。我们需要进行转换,因为它不知道它到底是什么类型。接下来是在事件处理程序中,我们使用的是Target
而不是AssociatedObject
,这是因为我们想编辑作为Target
的Slider
的值,而不是我们附加到的对象(AssociatedObject
)。 - 这是一个可选步骤。如果我们看之前检查是否有
行为
时的截图,你可能注意到没有对该行为
的解释。在这里我们将添加它[System.ComponentModel.Description("Target : Trigger. Responds to mousewheel event of attached object when focused. Manipulates slider values based on slider properties.")] public class EnableMouseWheel : TargetedTriggerAction<Slider> {
添加
特性 (attribute)
。生成并返回到Blend
中的 Mainpage.xaml。
使用行为
- 检查我们是否有了行为和描述
- 将
行为
附加到矩形
上,并在行为
的属性中,将Target
设置为其中一个滑块
。 - 现在运行,当你在矩形上滚动时,它应该会改变滑块。现在你已经完成了。
完整代码
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
namespace MouseWheelBehaviorLibrary
{
[System.ComponentModel.Description
("Target : Trigger. Responds to mousewheel event of attached object
when focused. Manipulates slider values based on slider properties.")]
public class EnableMouseWheel : TargetedTriggerAction<Slider>
{
//this method is required for the base class
protected override void Invoke(object parameter)
{
}
protected override void OnAttached()
{
base.OnAttached();
//add event handler to mouse wheel event
((FrameworkElement)AssociatedObject).MouseWheel +=
new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
}
protected override void OnDetaching()
{
base.OnDetaching();
//remove the event handler
((FrameworkElement)AssociatedObject).MouseWheel -=
new MouseWheelEventHandler(SliderMouseScroll_MouseWheel);
}
//this method runs on Mouse Wheel event
void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e)
{
//Delta = how much the wheel was scrolled. + for up - for down
//check to see if Delta is positive.
if (e.Delta > 0)
{
//using small change of Target(slider) property.
//this allows how much value can change from the designer
//
//alternatively you can actually use the delta value instead
//of forcing small change increments.
Target.Value = Target.Value + Target.SmallChange;
}
else //same as above just backwards
{
//using small change of Target(slider) property.
//this allows how much value can change from the designer
//
//alternatively you can actually use the delta value instead
//of forcing small change increments.
Target.Value = Target.Value - Target.SmallChange;
}
}
}
}
/////
/////
/////
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
namespace MouseWheelBehaviorLibrary
{
public class EnableSliderMouseWheel : Behavior<Slider>
{
protected override void OnAttached()
{
base.OnAttached();
//attach event handler on mouse wheel event
AssociatedObject.MouseWheel += new MouseWheelEventHandler
(SliderMouseScroll_MouseWheel);
}
protected override void OnDetaching()
{
base.OnDetaching();
//remove event handler on mouse wheel event
AssociatedObject.MouseWheel -= new MouseWheelEventHandler
(SliderMouseScroll_MouseWheel);
}
void SliderMouseScroll_MouseWheel(object sender, MouseWheelEventArgs e)
{
//Delta = how much the wheel was scrolled. + for up - for down
//check to see if Delta is positive.
if (e.Delta > 0)
{
//using small change of Target(slider) property.
//this allows how much value can change from the designer
//
//alternatively you can actually use the delta value instead
//of forcing small change increments.
AssociatedObject.Value = AssociatedObject.Value +
AssociatedObject.SmallChange;
}
else //same as above just backwards
{
//using small change of Target(slider) property.
//this allows how much value can change from the designer
//
//alternatively you can actually use the delta value instead
//of forcing small change increments.
AssociatedObject.Value = AssociatedObject.Value -
AssociatedObject.SmallChange;
}
}
}
}
注释
我发现 EnableMouseWheel
行为
存在一些兼容性问题,主要是在那些已经具有某种鼠标滚轮
支持的控件上。Combobox
似乎只有在所选索引为 -1
时才有效,而像 listbox
这样的控件似乎在滚动到列表末尾后才能正常工作。
有关行为的更多信息,请参阅 Silverlight Show。
感谢您的阅读,希望这对您有所帮助。这是我的第一篇文章,因此我非常欢迎您对文章或代码提出任何反馈。这是我在 CodeProject 上的第一篇文章。
历史
- 2010年7月7日:初次发布