WPF自定义控件构造,触发器和事件

G.Y*_*G.Y 12 .net c# wpf custom-controls wpf-controls

WPF自定义控件

我想构建一个新的自定义控件.我发现很少的教程给了我一些如何实现这一目标的线索.据我了解,创建一个新的自定义控件总是通过扩展当前控件来完成,甚至可以从层次结构的最基本级别扩展控件,例如,您甚至可以扩展:

  • 的UIElement
  • FrameworkElement的
  • 控制
  • ContentControl中
  • HeaderedContentControl
  • ItemsControl的
  • 选择
  • RangeBase

如以下教程中所述:http://wpftutorial.net/HowToCreateACustomControl.html

所以,我按照教程创建了一个自定义控件库类型的新项目,得到了我的通用.xaml和我的代码.到现在为止还挺好.

我可以区分3种类型或类别的事件.

  1. 可以使用我的控件的窗口(或容器)可以使用的事件:那些是我想要暴露给外部的事件.怎么写那些?

  2. 与控制本身相关但不暴露在外的事件; 例如,如果鼠标超出我的控制范围,我想对此做出反应.我可以在XAML中做到这一点:

    <ControlTemplate.Triggers>
      <Trigger Property="IsMouseOver" Value="true">  
        <Setter Property="Fill" TargetName="LeftTraingularIndicator">  
          <Setter.Value>  
            <SolidColorBrush Color="Yellow" />  
          </Setter.Value>  
        </Setter>
      </Trigger>
    </ControlTemplate.Triggers>  
    
    Run Code Online (Sandbox Code Playgroud)

假设我在我的ControlTemplate中有一个带有fill属性的元素,名为x:name ="LeftTraingularIndicator"

问题:

现在我想在我的XAML中对IsMouseDown做出反应.我怎么做?没有"IsMouseDown"触发器.此外,如果我想对后面的代码做出反应,该怎么办?如果我想从后面的代码中更改LeftTraingularIndicator"Fill",还有什么呢?

  1. 与子元素相关的事件是我的ControlTemplate视觉构造的一部分,例如,如果我想对XAML中的"LeftTraigularIndicator"的"IsMouseOver"做出反应,甚至在Code Behind中做出反应?也许两者都有.

我现在正在尝试2天......感觉我在理解事情如何运作时遗漏了一些东西.没有找到任何深入解释这些问题的教程.

我希望看到我在这里提出的每个问题的几行例子.

谢谢.

G.Y*_*G.Y 10

经过广泛研究......

1)将事件暴露给外部......就像你从任何其他阶级暴露出来一样.

public delegate void myDelegate(int someValue);  
public event myDelegate myEvent;
Run Code Online (Sandbox Code Playgroud)

在你的代码中的某个地方:

if(myEvent!=null)
  myEvent(5);
Run Code Online (Sandbox Code Playgroud)

那部分没什么新东西.

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.

}
Run Code Online (Sandbox Code Playgroud)

3)不推荐 - 因为它属于用户控件的范围而不是自定义控件.自定义控件是"原子",用户控件更适合组合控件的目的.

但并非不可能......

var myButton = (Button)Template.FindName("myButton",this);
myButton.OnMouseMove += ....
Run Code Online (Sandbox Code Playgroud)

请记住:

  • 必须在代码隐藏中找到任何应​​该知道的内容.

  • 你的xaml应该不知道背后的代码是做什么的.(除了! - 继续阅读)

  • 在设计XAML时,代码隐藏中应该知道的部件必须具有正确的名称.

我真的希望这会帮助那些在尝试开发自己的自定义控件时获得"墙"的人.


小智 7

如果我理解你的问题 - 以下是我的解释.

WPF事件系统提供3种类型的事件:1.冒泡2.隧道3.直接

如果事件(在内部)被定义为冒泡事件,则事件将从源传递到其容器.例如:如果Grid有两个按钮 - Rectangle1和Rectangle2,那么对这些矩形的任何点击都会向上冒泡到Grid.隧道是相反的,事件从父母隧道到孩子.

直接活动非常特别 - 它们仅适用于没有意义的活动.例如,在上面的场景中,在任一个矩形上冒泡MouseOver事件都没有意义 - 因为每次鼠标进入矩形时,事件都会冒泡到网格 - 这是人们可能期望的.

你的问题:

可以使用我的控件的窗口(或容器)可以使用的事件:那些是我想要暴露给外部的事件..如何编写这些事件?

你基本上需要写一个冒泡事件.下面是一个msdn的示例,用于在Button上写一个冒泡的tap事件(我自己没有尝试过)路由事件示例:

public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
"Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple));
Run Code Online (Sandbox Code Playgroud)

你的问题:

问题:现在我想在我的XAML中对IsMouseDown做出反应......我该怎么做?没有"IsMouseDown"触发器......如果我想对后面的代码做出反应,还有什么呢?如果我想从后面的代码中更改LeftTraingularIndicator"Fill",还有什么呢?

顺便说一下,你似乎对事件和触发器有些混淆(因为我看到你可以互换使用它们).虽然它们是相关的,但它们并不相同.

回到你的问题 - WPF允许触发属性更改 - 这实际上就是你要挂钩的 - 在这种情况下是IsMouseOver.但缺少的是该属性是ControlTemplate的目标(我不知道它是什么).我只是推断ControlTemplate的目标是一个Rectangle.在这种情况下,它没有"IsMouseDown"属性来挂钩属性触发器.这就是你无法找到它的原因.另一个选项你必须写一个AttachedEvent(它们与AttachedProperties非常相似)..另一个话题:(

我希望我尽我所能:)