Directory
Routing event Overview
WPF element tree
Event Routing
Routing events and combinations
Additional event
Route command Overview
Routing commands in operations
Command Routing
Define commands
Command insert
Limitations of routing commands
Avoid Command Errors
Beyond route command
Route ProcessingProgramExample
To get familiar with Windows Presentation Foundation (WPF) as soon as possible, you must have a lot of new structures to master. Even Microsoft. net Framework attributes and events. There are new corresponding items in WPF, and the functions are updated and more complex-especially dependency attributes and routing events, this feature is even more significant. There are also brand new content, such as animations, style settings, control templates, and routing commands. There are too many things to learn.
In this article, I will focus on two extremely important new WPF element items. These two elements are associated routing events and routing commands. They are the basis for communication between different components on the user interface-these components can be a single control of a large window class, or they can be controls that separate components on the user interface and their support Code . In this article, I assume that you have a certain understanding of WPF. For example, you know how to use the built-in WPF control and build the UI by declaring the UI layout in XAML.
Routing event Overview
When you get started with WPF, you may use a routing event if you do not know it. For example, when you add a button to the window in the Visual Studio designer and name it mybutton, and double-click the button, the click event is mounted within your XAML tag, its event handler is added to the Code hiding of the window class. This is similar to mounting events in Windows Forms and ASP. NET. In fact, it is close to ASP. NET Code compiling model, but it is more similar to the runtime model of Windows Forms. Specifically, in the XAML tag of a button, the end of the Code is similar to the following:
Copy code
<Button name = "mybutton" Click = "mybutton_click"> click me </button>
The XAML Declaration of the mounting event is like the attribute allocation in the XAML, but the result is a normal event hook for the object of the specified event handler. This hook actually appears in the partial class of the window generated during compilation. To view this hook, go to the constructor of the class, right-click the initializecomponent method call, and select "go to definition" from the context menu ". The editor displays the generated code file (which is named as. I. G. CS or. I. G. VB), including the Code normally generated during compilation. Scroll down to the Connect Method in the displayed local class and you will see the following content:
Copy code
# Line 6 "... \ .. \ window1.xaml"
This. mybutton. Click + =
New system. Windows. routedeventhandler (
This. mybutton_click );
This local class is generated from the XAML during compilation, which contains the XAML elements that need to be compiled during design. Most of the XAML will eventually become the binary resources embedded in the program after compilation, and will be merged with the compiled code represented by the binary mark at runtime.
If you look at the hidden code of the window, you will find the click handler as follows:
Copy code
Private void mybutton_click (
Object sender, routedeventargs e ){}
So far, it looks like any other. Net event hook-you have an explicitly declared delegate that is mounted to an object event and the delegate points to a processing method. The unique identifier of a routing event is the event parameter type of the click event, that is, routedeventargs. What are the unique characteristics of routing events? To understand this, you must first understand the WPF element combination model.
WPF element tree
If you open a new window in the project and drag the button into the window in the designer, you will get the element tree in the XAML format, as shown below (to clear the attribute ):
Copy code
<WINDOW>
<Grid>
<Button/>
</GRID>
</WINDOW>
Each element represents a runtime instance corresponding to the. NET type. The declarative hierarchy of elements forms a so-called logical tree. In addition, many controls in WPF are either contentcontrol or itemscontrol, which means they can have child elements. For example, a button is a contentcontrol that uses complex child elements as its content. You can expand the logic tree as follows:
Copy code
<WINDOW>
<Grid>
<Button>
<Stackpanel>
<Image/>
<Textblock/>
</Stackpanel>
</Button>
</GRID>
</WINDOW>
The generated UI 1 is shown in.
Figure 1 simple window containing button content
As you think, the tree can have multiple branches (another button in the grid), so the logic tree becomes extremely complex. For the WPF element of the logic tree, you need to realize that what you see is not what you actually get at runtime. Every such element is usually extended to a more complex visual element tree at runtime. In this example, the logical tree of an element is extended to a visual element tree, as shown in 2.
Figure 2 simple window visible tree
I used the tool named Snoop (Blois. US/snoop) to view the elements of the visual tree shown in figure 2. You can see that the eventswindow actually places its content in border and adornerdecorator, and uses contentpresenter to display its content. Similarly, the button places its content in the buttonchrome object, and then displays the content with contentpresenter.
When a single-click button is clicked, I may not actually click the button element at all. It may be that I click a child element in the visual tree, or even an element not displayed in the logic tree (such as buttonchrome ). For example, if I click the mouse over the image in the button. At the beginning, this click operation actually expresses it as the mouseleftbuttondown event in the Image Element. However, click events must be converted to button-level click events. This requires the introduction of routes in routing events.
Event Routing
It is necessary to understand the logic tree and the visual tree, because the routing event is routed based on the visual tree. Routing events support three routing policies: Bubble, tunnel, and direct.
Bubble events are most common. They represent events that spread (spread) from the source element to the visible tree until it is processed or reach the root element. In this way, you can process events for objects at the upper level of the source element. For example, you can attach a button. Click handler to an embedded grid element instead of directly attaching it to the button itself. A bubble event has a name indicating its operation (for example, mousedown ).
Tunnel events use another method, starting from the root element, traversing down the element tree until the source element of the event is processed or reached. In this way, the upstream element can be intercepted and processed before the event reaches the source element. According to naming conventions, a tunnel event has a prefix Preview (for example, previewmousedown ).
Direct events are similar to normal events in. NET Framework. The only possible handler for this event is the delegate associated with it.
Generally, if a tunnel event is defined for a special event, a bubble event is generated. In this case, the tunnel event is triggered first, starting from the root element, going down to the source element, and searching for the handler. Once it is processed or reaches the source element, it will trigger a bubble event, upstream from the source element, find the handler. Bubble or tunnel events do not stop routing only by calling the event handler. If you want to abort a tunnel or bubble process, you can use the event parameters you pass to mark the event as handled in the event handler.
Copy code
Private void onchildelementmousedown (Object sender,
Mousebuttoneventargs e ){
E. Handled = true;
}
Once your handler marks the event as handled, the event will not be passed to any other handler. This argument is only partially correct. In fact, Event Routing continues to work. You can use uielement. the replacement method of addhandler explicitly mounts the event handler in the Code. This method has an additional tag that can effectively indicate that "even if the event is marked as handled, you can call it ". You can use a call similar to the following to specify this note:
Copy code
M_somechildelement.addhandler (uielement. mousedownevent,
(Routedeventhandler) onmousedowncallmealways, true );
The first parameter of addhandler is the routedevent you want to process. The second parameter is the delegate to the event processing method (which requires the correct signature of the event Delegate. The third parameter indicates whether you want to receive a notification if another Handler has marked the event as handled. The element that you call addhandler is the element that observes the event flow during routing.
Routing events and combinations
Now let's take a look at the formation process of the button. Click Event to see why it is so important. As described above, you will use the mouseleftbuttondown event to start the click event for certain sub-elements in the button visual tree (such as the image in the previous example.
When the mouseleftbuttondown event occurs in the Image Element, previewmouseleftbuttondown is started in the root element, and then downstream along the tunnel to the image. If no handler is set as a preview event and the handled flag is set to true, mouseleftbuttondown will be propagated from the image element until it reaches the button. Button to handle this event, set handled to true, and then raise its own click event. The sample code in this article includes an application with the processing program of the entire route chain, which can help you view this process.
Its meaning cannot be underestimated. For example, if I choose to replace the default button appearance by applying a control template containing the ellipse element, the click event can be triggered by clicking outside ellipse. The outer Click close to ellipse is still within the rectangle border of my button, but ellipse has its own mouseleftbuttondown hit detection, while the blank area of the ellipse external button does not.
Because of this, the mouseleftbuttondown event is triggered only when you click within ellipse. It is still processed by the button class appended with this template. Therefore, even custom buttons can predict the behavior. This very important concept should also be kept in mind when writing custom composite controls, because your operations may be similar to how button handles events of child elements in the control.
Additional event
To enable elements to process events declared in different elements, WPF supports additional events. An additional event is a routing event. It supports element XAML mounting instead of declaring the type of the event. For example, if you want the grid to listen to the button. Click Event that uses bubbles, you only need to hook up as follows.
Copy code
<Grid button. Click = "mybutton_click">
<Button name = "mybutton"> click me </button>
</GRID>
The final code in the Local class generated during compilation is as follows:
Copy code
# Line 5 "... \ .. \ window1.xaml"
(System. Windows. Controls. Grid) (target). addhandler (
System. Windows. Controls. primitives. buttonbase. clickevent,
New system. Windows. routedeventhandler (this. mybutton_click ));
Additional events give you more flexibility in the location of the mounted event handler. However, if an element contains the same class (as shown in this example), the difference is not revealed because the processing method is still for the window class.
It has two impacts. First, the event handler calls an event based on the position of the processing element in the bubble or tunnel Element Chain. Second, you can perform additional operations, such as handling events from the encapsulated objects in the control. For example, you can process button. Click events as shown in the grid, but these button. Click events can be propagated from the user controls contained in the window.
Tip: Name the event handler
If you do not want to use the default name convention (objectname_eventname) of the event handler, you only need to enter the name of the event handler you need, right-click, click Browse to event handler in the context menu. Visual Studio then generates an event handler Based on the specified name.
In Visual Studio 2008 SP1, the "properties" window has an event view, which is similar to the view in Windows Forms. Therefore, if you have SP1, you can specify the event name there. However, if you use XAML, This is a convenient way to generate an explicitly named handler.
Generate an event handler (click an image to view the large image)
Not all events are declared as additional events. In fact, this is not the case for most events. However, when you need to process events outside of the control source, additional events can be of great help.
Route command Overview
You have seen the routing event. Next I will introduce the routing command. The WPF routing command provides a specific mechanism for you to mount UI controls such as toolbar buttons and menu items to the handler, you do not need to add many highly correlated duplicate codes to your application. Compared with normal event processing, routing commands have three advantages:
The routing command Source Elements (callers) can be separated from the command targets (handlers)-they do not need to be referenced by each other. If they are linked through event handlers, they need to be referenced by each other.
The handler indicates that when a command is disabled, the routing command automatically enables or disables all relevant UI controls.
You can use routing commands to associate keyboard shortcuts with other forms of input gestures (such as handwriting), as another way to call commands.
In addition, the routeduicommand class exclusive to routing commands can define a single text attribute and use command prompts for any controls (command invocation programs. The localization of text properties is easier than accessing the call control of each related program.
To declare a command on the calling program, you only need to set the command attribute on the control that triggers the command.
Copy code
<Button command = "applicationcommands. Save"> Save </button>
Menuitem, button, radiobutton, checkbox, hyperlink, and many other controls support the command attribute.
You can set commandbinding for the elements that you want to use as command handlers:
Copy code
<Usercontrol...>
<Usercontrol. commandbindings>
<Commandbinding command = "applicationcommands. Save"
Canexecute = "oncanexecute" executed = "onexecute"/>
</Usercontrol. commandbindings>
...
</Usercontrol>
The canexecute and executed attributes of commandbinding point to Methods hidden in the Declaration class code. These methods are called in the command processing process. The main point here is that the command caller neither needs to understand nor reference the command handler, And the handler does not have to know which element is going to call the command.
Call canexecute to determine whether the command should be enabled. To enable the command, set the canexecute attribute of the event parameter to true, as shown below:
Copy code
Private void oncanexecute (Object sender,
Canexecuteroutedeventargs e ){
E. canexecute = true;
}
For example, if the command Handler has a defined executed method but no canexecute method, the command is also enabled (in this case, canexecute is implicitly set to true ). Use the executed method to execute corresponding operations based on the called command. Such commands can be used to save documents, submit orders, and send emails.
Routing commands in operations
To make this concept more specific and bring immediate benefits to routing commands, let's look at a simple example. In Figure 3, you can see a simple UI with two input text boxes and a toolbar button for executing the cut operation on the text in the text box.
Figure 3 simple example of button in the cut command Toolbar
To use the event to complete the mounting, You need to define the click handler for the toolbar button, and the Code must reference two text boxes. You need to select which text box is the focus item based on the text in the control and call the corresponding clipboard operation. You can also enable or disable the toolbar button when appropriate based on the position of the focus item and whether there are options in the text box. The code is messy and complex.
For this simple example, the problem is not big, but what if these text boxes go deep into the interior of the user control or custom control and window code hiding cannot directly access them? You have to display the API at the border of the user control so that the container can be mounted or the text box can be exposed publicly. Either of them is not an ideal method.
To use commands, set the command attribute of the toolbar button to the cut command defined in WPF.
Copy code
<Toolbar dockpanel. Dock = "TOP" Height = "25">
<Button command = "applicationcommands. Cut">
<Image Source = "cut.png"/>
</Button>
</Toolbar>
Now, when you run the application, the toolbar button is disabled at the beginning. After a text box is selected, the toolbar button is enabled. If you click this button, the text is cut to the clipboard. This operation applies to any text box at any position in the UI. Oh, pretty good, right?
In fact, the textbox class implements a built-in command binding for the cut command, and encapsulates the clipboard processing of the command (copy and paste) for you. Then, how does a command only call the text box of interest, how does a message reach the text box, and tell it to process the command? This is where the routing components in the routing command play a role.
Command Routing
The difference between a routing command and a routing event is that a command routes a method from its calling program to a processing program. Specifically, a routing event routes messages from behind the scenes between the command invocation program and the Processing Program (by attaching it to the command binding in the visual tree ).
In this case, many elements are associated, but only one command handler is active at any time. The active command handler is determined by the position of the command invocation program and command handler in the visual tree, and the position of the focus item in the UI. The routing event is used to call the activity command handler to check whether the command should be enabled and to call the executed method handler of the command handler.
Generally, the command invocation program finds and binds the command between its position in the visual tree and the visual root item. If found, the bound command handler determines whether to enable the command and calls the processing sequence when calling the command. If the command is attached to a control in the toolbar or menu (or the focusmanager is set. isfocusscope = true), other logic is run, and the focus element bound to the command is viewed from the root item along the visual tree path.
In the simple application shown in figure 3, the actual situation is that, because the cut command button is located in the toolbar, canexecute and execute are processed by the textbox instance with the focus item. 3. If the text box is included in the user control, you will have the opportunity to bind the window, the user control that contains the grid, the user control that contains the text box, or a single text box setting command. The text box with a focus item determines the end point of its path (its starting point is the root item ).
To understand the routing of WPF routing commands, you must realize that once a command handler is called, you cannot call other handlers. Therefore, if the user control processes the canexecute method, it will not call the textbox canexecute implementation.
Define commands
Applicationcommands. Save and applicationcommands. Cut are two of the many commands provided by WPF. Figure 4 shows the five built-in command classes in WPF and some command examples contained in them.
Figure 4 WPF command class
Command class example command
Applicationcommands close, cut, copy, paste, save, print
Navigationcommands browseforward, browseback, zoom, search
Editingcommands alignxxx, movexxx, selectxxx
Mediacommands play, pause, nexttrack, increasevolume, record, stop
Componentcommands movexxx, selectxxx, scrollxxx, extendselectionxxx
Xxx represents the set of operations, such as movenext and moveprevious. Commands in each category are defined as public static (shared in Visual Basic) attributes so that you can easily mount them. You can easily define your own custom commands by using the following methods. I will provide examples later.
You can also use a short comment as follows:
Copy code
<Button command = "save"> Save </button>
If you use this short version, the type converter in WPF will try to find the named command from the built-in command set. In this example, the results are identical. I prefer to use a long-name version, which makes the code clearer and easier to maintain. There is no ambiguity in the definition location of the command. Even with built-in commands, there are some duplicates between the editingcommands class and the componentcommands class.
Command insert
A routing command is a special implementation of the icommand interface defined by WPF. Icommand is defined as follows:
Copy code
Public interface icommand {
Event eventhandler canexecutechanged;
Bool canexecute (object parameter );
Void execute (object parameter );
}
The built-in WPF command types are routedcommand and routeduicommand. These two types implement the icommand interface and use the routing event I introduced earlier to execute routing.
We expect the command invocation program to call canexecute to determine whether to enable any relevant command invocation code. The command caller can subscribe to the canexecutechanged event to determine when to call this method. In the routedcommand class, canexecutechanged is triggered based on changes in the status or focus item in the UI. When a command is called, The executed method is called and the routing events are distributed to the handler along the visible tree.
Supports the command Attribute Class (such as buttonbase) to implement the icommandsource interface:
Copy code
Public interface icommandsource {
Icommand command {Get ;}
Object commandparameter {Get ;}
Iinputelement commandtarget {Get ;}
}
The command attribute establishes an association between the caller and the command it calls. Commandparameter allows the caller to pass certain data while calling the command. You can use the commandtarget attribute to replace the default route based on the focus item path and notify the command system to use the specified element as the command handler, instead of relying on the decision made by the routing event and command handler Based on the focus item.
Limitations of routing commands
The routing command is ideal for single-user interfaces, attaching toolbar and menu items, and handling entries related to keyboard focus items (such as clipboard operations. However, if you want to build a complex user interface, that is, the command processing logic is in the support Code defined by the view, and the command calling program is not always in the toolbar or menu, in this case, the routing command is insufficient. Model View viewmodel (msdn.microsoft.com/library/cc707885) in a WPF loop, for example, Model View Controller, MVC, Model View presenter, MVP, and presentation model ), this usually happens.
At this point, the problem is that the logic for enabling and processing commands may not directly belong to the visual tree, but to the dashboard or model. In addition, determining whether to enable the command status is irrelevant to the position of the command caller and view in the visual tree. Sometimes, you may encounter a situation where a special command has multiple handlers at a given time.
For more information about the situations in which the routing command may fail, see Figure 5. It is a simple window that contains a pair of user controls. The two controls represent views in MVP or MVC mode. The main window contains a file menu and a toolbar with the Save command button. At the top of the main window, there is an input text box and a button that sets command as save.
Figure 5 composite User Interface (click an image to view the large image)
Tip: hook anonymous method
In the code shown in figure 6, I used the technique that my colleague Juval Lowy taught me to attach an empty anonymous method to the delegate in the Declaration.
Copy code
Action <string> m_executetargets = delegate {}; in this way, you do not have to check whether there is a null value before calling the delegate, because there is always a no-op subscribers in the call list. You may also cancel the subscription in a multi-threaded environment to avoid possible contention. If you check for null values, there will be frequent contention.
For more information about this technique, see programming. NET components, second edition by Juval Lowy.
The rest of the UI is provided by two views, each of which is an instance of a simple user control. The border colors of each user control instance are different, which is used to display the UI content they provide more clearly. Each user control instance has a Save button, which sets the command attribute to the Save command.
Routing commands (which are closely related to locations in the visual tree) bring difficulties in this simple example. In Figure 5, the window itself does not have a commandbinding for the SAVE command. But it does contain two calling programs (menus and toolbar) of the command ). In this case, I don't want the top-level window to know what to do when calling the command. The sub-view processing command that you want to represent by the user control. In this example, the user control class has a commandbinding for the SAVE command, which returns true for canexecute.
However, in figure 5, you can see that the focus item is located in the window in the top text box, and the command invocation program at this level is disabled. In addition, although the user control does not have a focus item, the Save button in the user control is enabled.
If you change the focus item from a text box to a user control instance, the command caller in the menu and toolbar changes to the Enabled state. However, the Save button of the window is not enabled. In fact, in this case, the Save button next to the text box above the window cannot be enabled with normal routing.
The reason is still related to the position of a single control. Because there is no command handler at the window level, although the focus item is outside the user control, however, if no command handler is found on the top of the visual tree or on the focus item path, the mounted control is enabled for the command invocation program. Once these controls are involved, commands are disabled by default. However, for the command calling program in the user control, the command is enabled because the handler is positioned on the top of the visual tree.
Once you move the focus item to one of the user controls, the user control located between the window and the focus item path provides a command handler to enable commands for the toolbar and menu, this is because they check the focus item path and the path between its position in the visual tree and the root item. This button cannot be enabled because there is no handler between the window-level button and the root item.
If the visual tree and the focus item path in this simple small example are too complex, in the visual tree, there are Command calling programs and processing programs in many different locations. to straighten out how difficult it is to enable and call commands, you can imagine. You may think of the plot in the scanners movie, which will be a little dizzy.
Avoid Command Errors
To prevent routing commands from having problems related to the position of the visual tree, you must keep it simple. Generally, make sure that the command handler is located on the same element or above the element that calls the command in the visual tree. You can use the commandmanager. registerclasscommandbinding method from the control that contains the life-order handler to add command binding at the window level, so as to achieve the above goal.
If you implement custom controls that accept keyboard focus items (such as text boxes), this is an exception. In this case, you can achieve this if you want to embed a command into the control and the command process is associated only when the focus item is on your control, its working conditions are similar to the preceding cut command example.
You can also use the commandtarget attribute to specify a command handler to solve the preceding problem. For example, for the Window Save button that has not been enabled in figure 5, you can change its command mounting to the following:
Copy code
<Button command = "save" commandtarget = "{binding elementname = uc1}" width = "75" Height = "25"> Save </button>
In this Code, the button specifically sets its commandtarget as a uielement instance, which contains a command handler. In this example, it specifies the element named uc1, Which is exactly one of the two user control instances in this example. Because this element has a command handler that always returns canexecute = true, the window-level Save button is always enabled and only the command handler of this control is called, this is true regardless of the location of the calling program relative to the command processing program.
Beyond route command
Due to restrictions on routing commands, many companies that use WPF to build complex UIS have switched to custom icommand implementation, which provides them with their own routing mechanisms, in particular, it is not associated with the visual tree and supports multiple command handlers.
It is not difficult to create custom commands. After the icommand interface is implemented for the class, a method is provided for the mounted command handler, and the route can be executed when the command is called. You must also determine the criteria used to determine when the canexecutechanged event is triggered.
It is best to use delegation before creating custom commands. The delegate supports calling the target method and multiple subscribers.
Figure 6 shows the command class named stringdelegatecommand, which uses a delegate to allow mounting of multiple handlers. It supports passing string parameters to the handler, and using the commandparameter of the caller to determine the messages passed to the handler.
Figure 6 custom command class
Copy code
Public class stringdelegatecommand: icommand {Action <string> m_executetargets = delegate {}; func <bool> m_canexecutetargets = delegate {return false ;}; bool m_enabled = false; public bool canexecute (object parameter) {delegate [] targets = m_canexecutetargets.getinvocationlist (); foreach (func <bool> Target in targets) {m_enabled = false; bool localenable = target. invoke (); If (localenable ){ M_enabled = true; break;} return m_enabled;} public void execute (object parameter) {If (m_enabled) m_executetargets (parameter! = NULL? Parameter. tostring (): NULL);} public event eventhandler canexecutechanged = delegate {};...}
As you can see, I choose to use func <bool> to delegate the handler to determine whether to enable the command. In the canexecute implementation, class traversal is linked to the handler entrusted by m_canexecutetargets to check whether there is a delegate to be executed by the handler. If yes, it returns true for the stringdelegatecommand to be enabled. When the execute method is called, it only needs to check whether the command is enabled. If it is enabled, it calls all the handlers that are attached to the m_executetargets action <string> delegate.
To mount the handler to the canexecute and execute methods, the stringdelegatecommand class exposes the event accessors shown in Figure 7, allowing the handler to easily subscribe to or unsubscribe from the underlying delegate. Note that you can use the event accesser to trigger the canexecutechanged event when processing the program subscription or canceling the subscription.
Figure 7 command event accessors
Copy code
Public event action <string> executetargets {Add {m_executetargets + = value;} remove {m_executetargets-= value;} public event func <bool> canexecutetargets {Add {signature + = value; canexecutechanged (this, eventargs. empty);} remove {m_canexecutetargets-= value; canexecutechanged (this, eventargs. empty );}}
Example of a route Handler
In the sample application for code download, I mounted this class. In this example, there is a simple view that implies a dashboard (which follows the MVP but does not have a model ). The dashboard exposes a representation model to the view to bind data (you can think of a representation model between the dashboard and the view, while the MVP model is behind the dashboard ). It indicates that the data attribute can be bound to a public view of the model. In this example, it only exposes one command attribute, so that you can easily implement mounting through data binding in the view's XAML.
Copy code
<Window X: class = "customcommandsdemo. simpleview"...> <grid> <button command = "{binding cookdinnercommand}" commandparameter = "Dinner is served! "...> Cook dinner </button> <button click =" onaddhandler "...> Add cook dinner handler </button> </GRID> </WINDOW>
The binding statement only searches for the attribute of the current datacontext (named cookdinnercommand). If it is found, it is passed to the icommand. We have mentioned commandparameter before. The caller can use it to pass some data along with the command. In this example, note that I only pass the string that will be passed to the handler through stringdelegatecommand.
The following figure shows how to hide the view code (window class ):
Copy code
Public partial class simpleview: window {simpleviewpresenter m_presenter = new simpleviewpresenter (); Public simpleview () {initializecomponent (); datacontext = m_presenter.model;} private void onaddhandler (Object sender, subject e) {m_presenter.addcommandhandler ();}}
View to build its dashboard, get the representation model from the dashboard, and set it to datacontext. It also has a button click handler, which calls the handler to add the handler for the command.
Figure 8 shows the running application. The first window is in the initial state and the command handler is not attached. Because there is no command handler, you will see that the first button (called Program) is disabled. When you press the second button, it calls the provisioner and attaches a new command handler. In this case, the first button is enabled. When you click it, it will call the command handler that is loosely connected through data binding and the subscription column table of the Basic command.
Figure 8 Examples of running custom commands (click an image to view the large image)
It is shown in code 9. You can see that the dashboard builds a representation model and exposes it to the view through the model attribute. When addcommandhandler is called from the view (in response to the second button click event), it adds a subscription to canexecutetargets and executetargets of the model. These subscription methods are simple methods in the tool. They return true and display MessageBox respectively.
Figure 9 indicates the device class
Copy code
Public class simpleviewpresenter {public simpleviewpresenter () {model = new simpleviewpresentationmodel ();} public simpleviewpresentationmodel {Get; set;} public void addcommandhandler () {model. cookdinnercommand. canexecutetargets + = canexecutehandler; model. cookdinnercommand. executetargets + = executehandler;} bool canexecutehandler () {return true;} void executehandler (string MSG) {MessageBox. show (MSG );}}
This example shows that the combination of data binding, UI mode, and custom commands will bring you a clear and independent command path, and you can get rid of the restrictions of routing commands. Because commands are mounted in the XAML format by binding, you can even use the XAML to define the view completely in this way (no code is hidden) use the binding command from XAML to trigger the operation in the model, and start the operation that you originally needed to hide and execute the model code.
You need a controller to build a view and provide it with a representation model, but you can write an interactive view without hiding the code. If you do not need to hide the code, the machine rate of adding complex codes that are tangle with each other and cannot be tested in the Code hiding file will be greatly reduced. This often occurs in Ui applications. This method has just been used in WPF. But it is worth considering. You should know more examples.
Code download (175 KB)
this article from the csdn blog, reprinted please indicate the source: http://blog.csdn.net/wmjcom/archive/2009/05/22/4208406.aspx