Reducing the coupling of logic and UI elements in WPF

Source: Internet
Author: User

Text: Reduce the coupling of logic and UI elements in WPF

in the Reduce The coupling between logic and UI elements in WPF

Zhou Banhui

1, avoid referencing interface elements in logic, and do not impose background data on the UI

a bad case.

For example, the main interface has a label label_taskstate that shows the status of the current task , and we will update the label frequently to notify the user of the task status in a timely manner. So it's a bad assumption that our code will be flooded with such statement segments This.label_taskstate. Content = this. Getstatedescription (TASKSTATES.BUSY); ( The Getstatedescription method returns a relatively friendly description)

When the user clicks on the "Pause" button, we may want to update the label like this:

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 something goes wrong with our task for some reason, we might:

Try

{

Do something Dangerous

}

catch (MyException e)

{

This.label_taskstate. Content = this. Getstatedescription (Taskstates.error);

}

Finally

{

...

}

In this way , our logic code will reference label_taskstate this UI element in countless places .

Now there are some changes: (1) We feel that using a piece of text to describe the status of the task is not intuitive enough, 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 do not care). (2) on the other panel (MyPanel2) also to put a display task current task status of the label Label_taskstate2, but it only shows the text description can be.

So are we supposed to modify our code like this in such a bad environment?

first find out where all the label_taskstate are referenced (for example, there are three).

then the The lable type of the label_taskstate control is modified to the Image type of the image_taskstate control.

then repeat the this.label_taskstate. Content = this. Getstatedescription (TASKSTATES.BUSY); The statement is replaced with This.image_TaskState.Source = this. Getstateimage (taskstates.busy);

don't forget to append one at a time after the statement:this.label_TaskState2.Content = this. Getstatedescription (TASKSTATES.BUSY); because we have added a label.

What an angry programming job it is.

The reason is that we frequently refer to unstable interface elements (label_taskstate), which seriously coupled the interface and logic, and we use the assignment to impose the background data (the current state information) on the UI element.

Solution: Use Binding, and then the UI element "takes" data from the background

A simple description is: background logic to the foreground The UI says, "It's up to the front desk to show the data .

"The data is here."

Our data is the status information of the current task, in order to provide UI elements and background logic used, we decided to provide a thetaskstate property to track the current state:

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));

This allows the background logic to change the state of the task only need to modify the Thetaskstate property is available.

"I'll take it with you."

The current station needs to show the state of the task to the user only need to read this property, to real-time tracking on the binding bar.

<label x:name= "Label_taskstate"

Content= "{Binding elementname=windowmain,path=thetaskstate}"/>

"How to show a decision by the front desk"

No, I'm going to show it to the user. Not some enumeration values, but should be pictures or text.

That's true, so we're going to add converters (or data templates, here we use converters) to the bindings:

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 back-end logic does not refer to UI element and imposes the data on it, the background focuses on how the task status and its updates, and the foreground focuses on how to present the information to the user. When we want to change the other display mode, we just need to change the converter.

2, Avoid logic code dependency Template the elements in

The purpose of the template is replaceable, and if it is coupled with logic, it is very likely that when the template is replaced with an exception, which is not replaceable, templates lose meaning.

a bad case 1

For example, let's build ScrollBar Such a control, if the user clicks the arrows on the ScrollBar at the end of the line as follows, the problem will occur: in ScrollBar 's ControlTemplate of the visual tree are placed on both ends of a ToggleButton, so that users click on the two buttons can be up and down (or left or right) page, how to handle the user's click events? The wrong way is to register the button's Click event:

private void Repeatbutton1_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

}

a bad case 2

Sometimes we make mistakes like this: we've been using them a lot. ControlTemplate(DataTemplate is the same) to separate the logic and UI nicely (e.g. we've built a nice custromcontrol), But suddenly it seems like you want to reference an element in the ControlTemplate visual tree in logical code, and then discover that Frameworktemplate.findname () can do the work, The following code appears:

<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 can all finish the work, but we know in in WPF, users (your control users, or perhaps yourself) can customize ControlTemplate , so users can simply delete or change the two RepeatButton that are logically referenced to other elements. Then the control must be incomplete or even abnormal. If you do not allow user changes, you lose the meaning of the Template.

Solution:

experience is that when you feel the need to register an event with an element in the visual tree to hook up to an event-handling method, you can think of ways to wrap the functionality implemented by the method into Command. For example , in case 1, you can flip the top and bottom (or left or right) of the scroll bar into the form of Scrollbar.lineupcommand,Scrollbar.linedowncommand, Then simply assign the Command property of the element in the visual tree that represents the top and bottom page to them. If only one of the elements of an event will change the state of certain elements (or their own), you can use Trigger to achieve this (perhaps you need to add some Dependency property to act as Trigger conditions), such as:

<ControlTemplate.Triggers>

<trigger property= "IsEnabled" value= "false" >

<setter property= "Background" targetname= "Bg" value= "Red"/>

</Trigger>

</ControlTemplate.Triggers>

There is absolutely no excuse for the logical part to refer DataTemplate elements that may logically refer to elements in contorltemplate (when creating certain CustomControl ), you can use the Templatepartattribute to be identified.

Build CustomControl When you encounter the coupling problem, you can refer to this article: Customizing Controls in WPF (3) CustomControl ( bottom )

3, Summary

in general, we should be logical and The decoupling of the UI,WPF also provides us with such a mechanism. The above example shows only a few common situations, and the solution provided is for informational purposes only, and there is no universal solution, because it involves too many small tricks that fit into different situations. But overall: data binding,Style,Template,Command,Resource, etc. provide several ways to decouple the logic and UI. If you find that your logic code and UI elements are seriously coupled together and cause a lot of trouble, you can start with a few of the above approaches. In addition, the main purpose of writing this text is to arouse people 's attention to the decoupling of logic and UI in the actual coding process .

Reducing the coupling of logic and UI elements in WPF

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.