WPF 自定义控件构造、触发器和事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14951435/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF Custom Controls Construction,Triggers and Events
提问by G.Y
I want to build a new custom control. I found few tutorials that gave me some clue of how to achieve this. As I understand it, creating a new custom control is always done by extending a current one, and it is even possible to extend a control from the very basic levels of the hierarchy, in example, you can even extend:
我想构建一个新的自定义控件。我发现很少有教程可以让我了解如何实现这一目标。据我了解,创建新的自定义控件总是通过扩展当前控件来完成的,甚至可以从层次结构的非常基本的级别扩展控件,例如,您甚至可以扩展:
- UIElement
- FrameworkElement
- Control
- ContentControl
- HeaderedContentControl
- ItemsControl
- Selector
- RangeBase
- 用户界面元素
- 框架元素
- 控制
- 内容控制
- 标题内容控件
- 项目控制
- 选择器
- 范围基础
As written in the following tutorial: http://wpftutorial.net/HowToCreateACustomControl.html
如以下教程中所写:http: //wpftutorial.net/HowToCreateACustomControl.html
So, I followed the tutorial and created a new project of type Custom Control Library, got my generic .xaml and my code behind. So far so good.
所以,我按照教程创建了一个自定义控件库类型的新项目,得到了我的通用 .xaml 和我的代码。到现在为止还挺好。
There are 3 types or categories of events I can distinguish between.
我可以区分 3 种类型或类别的事件。
Events that are consumable by the window (or container) that will use my control: those are the events I would like to expose to the outside. How to write those?
Events that are related to the control itself and not being exposed outside; for example, if the mouse is over my control and I would like to react to that. I can do that in the XAML:
<ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="true"> <Setter Property="Fill" TargetName="LeftTraingularIndicator"> <Setter.Value> <SolidColorBrush Color="Yellow" /> </Setter.Value> </Setter> </Trigger> </ControlTemplate.Triggers>
由将使用我的控件的窗口(或容器)消耗的事件:这些是我想向外部公开的事件。这些怎么写?
与控件本身相关且未暴露于外部的事件;例如,如果鼠标悬停在我的控制上方,而我想对此做出反应。我可以在 XAML 中做到这一点:
<ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="true"> <Setter Property="Fill" TargetName="LeftTraingularIndicator"> <Setter.Value> <SolidColorBrush Color="Yellow" /> </Setter.Value> </Setter> </Trigger> </ControlTemplate.Triggers>
Assuming of couse I have an element with the fill property in my ControlTemplate which is named x:name="LeftTraingularIndicator"
假设我的 ControlTemplate 中有一个带有 fill 属性的元素,该元素名为 x:name="LeftTraingularIndicator"
Questions:
问题:
Now I want to react in my XAML to IsMouseDown. How do I do that? There is no "IsMouseDown" Trigger. Furthermore what if I want to react to that in the code behind? And even further what if I want to change LeftTraingularIndicator "Fill" from the code behind?
现在我想在我的 XAML 中对 IsMouseDown 做出反应。我怎么做?没有“IsMouseDown”触发器。此外,如果我想对后面的代码做出反应怎么办?更进一步,如果我想从后面的代码中更改 LeftTraingularIndicator“Fill”怎么办?
- Events that related to sub-elements which are part of the visual construction of my ControlTemplate, in example what if I want to react to "IsMouseOver" of "LeftTraigularIndicator" in XAML / or even in Code Behind? Maybe even both.
- 与子元素相关的事件,这些子元素是我的 ControlTemplate 的可视化结构的一部分,例如,如果我想对 XAML/甚至代码隐藏中的“LeftTraigularIndicator”的“IsMouseOver”做出反应怎么办?甚至可能两者兼而有之。
I am attempting for 2 days now... feeling I am missing something in my understanding of how things work. Didn't find any tutorial that deeply explains those questions.
我现在尝试了 2 天......感觉我在理解事物的运作方式方面缺少一些东西。没有找到任何深入解释这些问题的教程。
I would like to see a few lines of example for each of the questions I surfaced here.
对于我在这里提出的每个问题,我想看到几行示例。
Thanks.
谢谢。
采纳答案by G.Y
After extensive research...
经过广泛的研究...
1) Exposing events to the outside... Simply as if you were exposing from any other class.
1) 向外界公开事件...就像您从任何其他类中公开一样。
public delegate void myDelegate(int someValue);
public event myDelegate myEvent;
and somewhere in your code:
并在您的代码中的某处:
if(myEvent!=null)
myEvent(5);
Nothing new in that part.
那部分没有什么新东西。
2) From the code behind create an instance constructor
2)从后面的代码创建一个实例构造函数
public MyCustomControl()
{
MouseMove += MyCustomControl_MouseMove;
}
void MyCustomControl_MouseMove(object sender, MouseEventArgs e)
{
//now you can react to the movement of the mouse.
//if for example I want to address an element, let's say a rectangle:
var ele = (Rectangle)Template.FindName("myRect",this);
ele.Fill=myNewBrush;
// provided that we have an element named "myRect" (x:name="myRect") in
// the generic.xaml style->Control Template-> which corresponds to that name.
}
3) Not recommended - as it belong to the scope of user-controls and not custom controls. Custom controls are the "atoms", user controls are more suitable to the purpose of combining controls.
3) 不推荐 - 因为它属于用户控件的范围而不是自定义控件。自定义控件是“原子”,用户控件更适合组合控件的目的。
But not impossible...
但并非不可能...
var myButton = (Button)Template.FindName("myButton",this);
myButton.OnMouseMove += ....
Just keep in mind that:
请记住:
Anything that should be known in the code-behind must be named.
Your xaml should have no knowledge of what the code behind do. (except! - keep reading)
Parts that should be known in the code-behind must have the correct name when you design your XAML.
任何应该在代码隐藏中知道的东西都必须被命名。
您的 xaml 应该不知道背后的代码是做什么的。(除了! - 继续阅读)
在设计 XAML 时,代码隐藏中应该知道的部分必须具有正确的名称。
I truly hope this will help others who get a "wall" when trying to develop their own custom-controls.
我真的希望这会帮助那些在尝试开发自己的自定义控件时遇到“墙”的人。
回答by Sam Vemagiri
If I understood your question correctly - the below is my explanation.
如果我正确理解了您的问题 - 以下是我的解释。
WPF event system offers 3 types of events: 1. Bubbling 2. Tunneling 3. Direct
WPF 事件系统提供 3 种类型的事件:1. 冒泡 2. 隧道 3. 直接
If an event is defined (intrensically) as a bubbling event, then the event is bubbled up from the source to its container. For eg: If a Grid hosts two buttons - Rectangle1 and Rectangle2, then any click on these rectangles is bubbled up to the Grid. Tunneling is the opposite, where events tunnel from parent to the child.
如果一个事件(本质上)被定义为冒泡事件,则该事件从源冒泡到其容器。例如:如果一个 Grid 有两个按钮 - Rectangle1 和 Rectangle2,那么在这些矩形上的任何点击都会冒泡到 Grid。隧道是相反的,事件从父到子隧道。
There are Direct events which are very special - they are only applicable where events do not make sense to be bubbled up. For eg, in the above scenario, it doesnt make sense to bubble up the MouseOver event on either of Rectangles - because every time the mouse enters the rectangle the event is bubbled up to the Grid - which is what someone might expect.
有一些非常特殊的直接事件 - 它们仅适用于事件没有意义冒泡的情况。例如,在上述场景中,在任一矩形上冒泡 MouseOver 事件是没有意义的 - 因为每次鼠标进入矩形时,事件都会冒泡到 Grid - 这可能是某些人所期望的。
Your Question:
你的问题:
Events that are consumable by the window (or container) that will use my control: those are the events I would like to expose to the outside.. how to write those?
由将使用我的控件的窗口(或容器)消耗的事件:这些是我想向外部公开的事件..如何编写这些事件?
You basically need to write a bubbling event. Below is an example from msdn to write a bubbling tap event on a Button (I have not tried it myself) Routed event example:
你基本上需要写一个冒泡事件。下面是来自 msdn 的示例,用于在按钮上编写冒泡点击事件(我自己没有尝试过)路由事件示例:
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
"Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple));
Your Question:
你的问题:
Questions: Now I want to react in my XAML to IsMouseDown... how do I do that? there is no "IsMouseDown" Trigger.. further more what if I want to react to that in the code behind? and even further what if I want to change LeftTraingularIndicator "Fill" from the code behind?
问题:现在我想在我的 XAML 中对 IsMouseDown 做出反应……我该怎么做?没有“IsMouseDown”触发器……如果我想对后面的代码做出反应,该怎么办?甚至如果我想从后面的代码中更改 LeftTraingularIndicator“Fill”怎么办?
BTW, you seem to have some confusion with events and triggers (because I see you use them interchangeably). Although they are related, they are not the same.
顺便说一句,您似乎对事件和触发器有些困惑(因为我看到您可以互换使用它们)。虽然它们有关联,但它们并不相同。
Getting back to your question - WPF allows for triggers on property changes - which is what essentially you are hooking to - IsMouseOver in this case. But what is missing is that the property is of the target of the ControlTemplate (which I dont know what it is). I am just extrapolating that the target of the ControlTemplate is a Rectangle. In which case, it does not have a "IsMouseDown" property for you to hook a property trigger. And that is the reason you cannot find it. The other option you have to write an AttachedEvent (they are very similar to AttachedProperties).. a whole another topic :(
回到您的问题 - WPF 允许触发属性更改 - 在这种情况下,这基本上是您要挂钩的 - IsMouseOver。但是缺少的是该属性是 ControlTemplate 的目标(我不知道它是什么)。我只是推断 ControlTemplate 的目标是一个矩形。在这种情况下,它没有“IsMouseDown”属性供您挂钩属性触发器。这就是你找不到它的原因。您必须编写一个 AttachedEvent 的另一个选项(它们与 AttachedProperties 非常相似)...完全是另一个主题:(
I hope I tried my best :)
我希望我尽力了:)

