Reduce coupling between logic and UI elements in WPF

Source: Internet
Author: User

InWPFReduce logic andUIElement Coupling

Zhou yinhui

1,Avoid referencing interface elements in logic, and do not impose background data onUI

 A bad case

For example, there is a label on the main interface that shows the status of the current task.Label_taskstate, We will update this label from time to notify users of the task status. A bad assumption is thatCodeSuch statement segments are everywhere.This. label_taskstate. content = This. getstatedescription (taskstates. Busy );(GetstatedescriptionMethod returns a friendly description)

When a user clicks the pause button, we may want to update the tag as follows:

Void btn_pause_clicked (Object sender, routedeventargs E)

{

// Do something to pause the task

// Update our lab

This. label_taskstate. content = This. getstatedescription (taskstates. Pause );

}

When an error occurs in our task for some reason, we may do this:

Try

{

// Do something dangerous

}

Catch (myexception E)

{

This. label_taskstate. content = This. getstatedescription (taskstates. Error );

}

Finally

{

//...

}

In this way, our logic code will be referenced in countless placesLabel_taskstateThisUIElement.

There are some changes :(1We think it is not intuitive to use a piece of text to describe the task status, so we decided to use a series of beautiful icons provided by the artist to display the current status (the icon may also contain text, but we don't care about it ). (2) On another panel (Mypanel2) You must also place a label that displays the current task status of the task.Label_taskstate2,It only displays the text description.

So should we modify our code like this in such a bad environment?

First, find all referencesLabel_taskstate(For example20).

ThenLableTypeLabel_taskstateControlImageTypeImage_taskstateControl.

Then repeatThis. label_taskstate. content = This. getstatedescription (taskstates. Busy );Replace statementThis. image_taskstate.source = This. getstateimage (taskstates. Busy);

Do not forget to append an entry after this statement every time:This. label_taskstate2.content = This. getstatedescription (taskstates. Busy );Because we have added a label.

What a hot programming job.

The reason is that we frequently reference unstable interface elements (Label_taskstate), Seriously coupled the interface and logic, we use the value assignment method to impose background data (current status information) onUIElement.

Solution: UseBinding, HoweverUIElements are retrieved from the background

A simple description is: the background logic isUI"It is up to the front-end to decide how to display the data. You can use the data here"

"Data is here"

Our data is the status information of the current task.UIWe decided to provideThetaskstateAttribute to track the current status:

Public taskstates thetaskstate

{

Get

{

Return (taskstates) getvalue (thetaskstateproperty );

}

Set

{

Setvalue (thetaskstateproperty, value );

}

}

Public static readonly dependencyproperty thetaskstateproperty =

Dependencyproperty. Register ("thetaskstate", typeof (taskstates ),

Typeof (window1), new uipropertymetadata (taskstates. idle ));

In this way, you only need to modify the task status in the background logic.ThetaskstateAttribute.

"If you want to use it, take it by yourself"

The current server only needs to read this attribute when displaying the task status to the user. to track the task in real time, bind it.

<Label X: Name = "label_taskstate"

Content = "{binding elementname = windowmain, Path = thetaskstate}"/>

"How to display is determined by the front-end"

No. The enumerated values I want to display to users are not images or text.

So we need to add the converter (or data template, here we use the converter) to the binding ):

Public class taskstatesimageconverter: ivalueconverter

{

Public object convert (object value, type targettype, object parameter, system. Globalization. cultureinfo Culture)

{

Taskstates state = (taskstates) value;

Return getimagefromtaskstate (State );

}

Public object convertback (object value, type targettype, object parameter, system. Globalization. cultureinfo Culture)

{

Throw new notimplementedexception ();

}

Private image getimagefromtaskstate (taskstates state)

{

Image image = new image ();

Image. Source = new bitmapimage (New uri (INT) State + ". PNG", urikind. Relative ));

Return image;

}

}

<Label X: Name = "label_taskstate"

Content = "{binding elementname = windowmain,

Path = thetaskstate,

Converter = {staticresource mytaskstatesimageconverter} "/>

In this way, our background logic is not referencedUIThe background focuses on how the task status and updates, and the foreground focuses on how to present the information to the user. When we want to change other display methods, we only need to change the converter.

2,Avoid logical code dependencyTemplateElement in

TemplateThe purpose is to be replaceable. If it is coupled with logic, it is likely to be replaced.TemplateWhen an exception occurs, that is, the template cannot be changed.

Bad Cases1

For example, let's buildScrollbarIf the user clicksScrollbarThe arrows at both ends will cause a problem:ScrollbarOfControltemplateThe two ends of the visual tree are placed with oneTogglebuttonSo that users can click these two buttons to flip pages up or down (or left or right). How can we deal with user click events? The incorrect method is to register the Click Event of the button:

Private void repeatbutton#click (Object sender, routedeventargs E)

{

Repeatbutton RB =(Repeatbutton)Sender;

// Left (or up) scrolling

}

Private void repeatbutton2_click (Object sender, routedeventargs E)

{

Repeatbutton RB =(Repeatbutton)Sender;

// Right (or down) scrolling

}

Bad Cases2

Sometimes we make the following mistake: we have followed many rules to use it.Controltemplate(DatatemplateIs the same .)UIVery good separation (for example, we have created a goodCustromcontrol), But suddenly it seems to be referenced in the logic code.ControltemplateAn element in the visual tree, and then findFrameworktemplate. findname ()The following code can be used to complete this task:

<Style targettype = "{X: type button}">

<Setter property = "template">

<Setter. value>

<Controltemplate targettype = "{X: type button}">

<Grid margin = "5" name = "Grid">

<! -- Someting else -->

</GRID>

</Controltemplate>

</Setter. value>

</Setter>

</Style>

Grid gridintemplate = (GRID) mybutton1.template. findname ("Grid", mybutton1 );

// Do something about the grid

These tasks can be completed, but we know thatWPFUsers (your control users, or yourself) can be customized.ControltemplateThen you can reference the two logical references.RepeatbuttonIf you delete or replace it with other elements, the controls must be incomplete or even abnormal. If the user is not allowed to change it, it will be lost.Template.

Solution:

Experience is that when you think that you must register the elements in the visual tree to link them to an event processing method, you can try to encapsulate the functions implemented by the methodCommand. For example, case1, You can wrap up or down the scroll bar (or left or right) pages, suchScrollbar. lineupcommand,Scrollbar. linedowncommandIn the formCommandYou can set the attribute to them. You can useTriggerTo achieve this goal (you may need to addDependency PropertyTo actTrigger), Such:

<Controltemplate. triggers>

<Trigger property = "isenabled" value = "false">

<Setter property = "background" targetname = "BG" value = "red"/>

</Trigger>

</Controltemplate. triggers>

There is absolutely no excuse to make the logic part referenceDatatemplateMay have logical references.ContorltemplateElement (create someCustomcontrolIn this case, you can useTemplatepartattribute.

BuildCustomcontrolFor the coupling problem, refer to this article.Article:InWPFCustom Controls(3) customcontrol (Lower)

3,Summary

in general, we should work hard to decouple the logic from UI , WPF also provides us with such a mechanism. The above example only illustrates several common situations, and provides solutions for reference only. There is no universal solution, because it involves too many tips to adapt to different situations. But in general: Data Binding, style , template , command , resource et al. provide several ways to decouple logic and UI , if you find that your logic code and UI elements are seriously coupled, which brings a lot of trouble, you can start from the above several ways. In addition, the main purpose of writing this text is to draw attention to the logic and UI decoupling in the actual coding process.

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.