Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Custom Controls Construction,Triggers and Events

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

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.

There are 3 types or categories of events I can distinguish between.

  1. 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?

  2. 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>  
    

Assuming of couse I have an element with the fill property in my ControlTemplate which is named 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?

  1. 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.

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.

I would like to see a few lines of example for each of the questions I surfaced here.

Thanks.

like image 720
G.Y Avatar asked Feb 19 '13 06:02

G.Y


People also ask

What is the difference between user control and custom control in WPF?

A customControl can be styled and templated and best suited for a situation when you are building a Control Library. On the contrary, a UserControl gives you an easy way to define reusable chunk of XAML which can be reused widely in your application and when you don't need to use it as a Control Library .


2 Answers

After extensive research...

1) Exposing events to the outside... Simply as if you were exposing from any other class.

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

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.

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.

I truly hope this will help others who get a "wall" when trying to develop their own custom-controls.

like image 199
G.Y Avatar answered Sep 22 '22 14:09

G.Y


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

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.

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.

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:

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?

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 :(

I hope I tried my best :)

like image 44
Sam Vemagiri Avatar answered Sep 26 '22 14:09

Sam Vemagiri