Convert the event of the control in WPF to command for execution)

Source: Internet
Author: User

WPF databinding facilitates the separation of view and logic. In particular, the MVP mode allows you to bind most of the UI interaction logic to the command
So that we can focus on operating business data. However, many widgets provided by Microsoft do not have the command attribute,
Only common events are supported. In this case, there is no way to use the binding to transfer the logic to the presenter. See The XAML. CS (codebehind file of each XAML file) File
There are still a lot of event processing code that is very uncomfortable, so I thought of a way to convert event processing into executing command, so that we can process it in presenter.
Logic of eventhandler. Only one constructor In The XAML. CS file feels good, and the view and logic are truly separated.
First, let's take a look at how to write in XAML using this method.
<Button commandbindingbehavior. bindingeventname = "click"
Commandbindingbehavior. bindingcommand = "{binding closemainwindowcommand}" content = "eventtocommand"/>
The two attachproperties are used in the button. When the click event is triggered, the commands you bind will also be executed, and you do not need to write for the click event.
Any processing program.
Next, let's take a look at what these two attachproperties have done.
In fact, the idea is very simple: Reflection in dependencyobject using this additional property in the propertychanged event of the bindingeventname additional Property
Find the event specified by bindingeventname and register a handler for it. The function body of the event processing function is bound to the bindingcommand attribute.
Command. In this way, the bound command can be executed when the event is executed. On the surface, it is optimistic that the event is converted to the command for execution.
(You may think it is too simple. In fact, the specific implementation process is not that easy .)
Step 1: define two attachproperties (bindingeventnameproperty and bindingcommandproperty );
Bindingeventnameproperty is used to save the event name to be converted to command execution;
Bindingcommandproperty is used to bind the command to be executed.
Public static class commandbindingbehavior
{
Public static dependencyproperty bindingeventnameproperty =
Dependencyproperty. registerattached ("bindingeventname", typeof (string ),
Typeof (commandbindingbehavior), new propertymetadata (null, onbindingeventchanged ));
Public static dependencyproperty bindingcommandproperty =
Dependencyproperty. registerattached ("bindingcommand", typeof (icommand), typeof (commandbindingbehavior), new propertymetadata (null ));
}
Step 2: Write a common event processing method. Why is it generic, because it is registered to all types of events as a processing function.
Private Static void oneventraised <t> (Object sender, t Arg) where T: eventargs
{
Dependencyobject = sender as dependencyobject;
If (dependencyobject! = NULL)
{
Icommand command = getbindingcommand (dependencyobject );
If (command. canexecute (null ))
{
Command. Execute (null );
}
}
}
According to my observations, the signatures of the event handler of the UI control are almost all void eventhandlermethodname (Object sender, t Arg) where T: eventargs;
Why do we need to define such a function? skip this step and you will understand it after completing step 3.
Step 3: implement the onbindingeventchanged event handler (the most critical step)
Private Static void onbindingeventchanged (dependencyobject sender, dependencypropertychangedeventargs Arg)
{
Type sendertype = sender. GetType ();
Eventinfo = sendertype. getevent (Arg. newvalue. tostring ());
Eventinfo. addeventhandler (sender, generatedelegateforeventhandler (eventinfo, true ));
}
Method description:
Get the event specified by bindingeventname from the sender through reflection, and then add a handler for it by calling addeventhandler.
The second parameter of addeventhandler is to pass a delegate. In this case, a problem occurs: the signatures of different event handlers are different,
If you write a common method (such as the implemented oneventraised), even if it is defined as a generic type, it cannot be converted to a specific delegate.
It seems that you can only dynamically obtain the signature of the handler Based on the event type, and then dynamically create a method.
Let's take a look at the implementation of the generatedelegateforeventhandler method:
Private Static delegate generatedelegateforeventhandler (eventinfo)
{
Delegate result = NULL;
Methodinfo = eventinfo. eventhandlertype. getmethod ("INVOKE ");
Parameterinfo [] parameters = methodinfo. getparameters ();
If (parameters. Length = 2)
{
Type currenttype = typeof (commandbindingbehavior );
Type argtype = parameters [1]. parametertype;
Methodinfo eventraisedmethod =
Currenttype. getmethod ("oneventraised", bindingflags. nonpublic | bindingflags. Static). makegenericmethod (argtype );
Result = delegate. createdelegate (eventinfo. eventhandlertype, eventraisedmethod );
}
Return result;
}
Method description:
This method ends an eventinfo object. The eventinfo object contains an eventhandlertype attribute, that is, the delegate type of the event handler ).
Then get the delegate invoke method through reflection. (The signature of each delegate invoke method is the same as that of the delegate method, so we can use
This method is used to determine the delegate signature)
We get the parameter type of the invoke method through reflection (the first parameter is the object type, and the second parameter type is useful );
The delegate class has a createdelegate method. Its prototype is as follows:
Createdelegate (type, methodinfo );
By accepting a delegate type and a method described by methodinfo, you can create a delegate object specified by the type.
So now the key is how to generate this methodinfo object.
The oneventraised generic method we created previously can now be used. We can get the methodinfo of this method through reflection.
But this object is not what we want, because the type of its second parameter is different from the signature of the target delegate.
Makegenericmethod of methodinfo can help us replace generic parameters in oneventraised with specific parameters, so that we can use
The type of the second parameter of the delegate invoke method is generated into a useful methodinfo.
Note: The delegate and multicastdelegate classes do not have the invoke method. Why can we get
What about the Delegate-type invoke method? In fact, this is what the compiler is doing. The compiler will create invoke, begininvoke and endinvoke for each delegate object.
Method.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.