XAML: Best practices for event processing in custom controls, and best practices for xaml

Source: Internet
Author: User

XAML: Best practices for event processing in custom controls, and best practices for xaml

In developing a XAML (WPF/UWP) application, sometimes we need to create a Custom Control to meet actual needs. In custom controls, we generally use some native controls (such as buttons and TextBox) to help complete the functions of custom controls.

Unlike a User Control, a custom Control uses Code-Behind (where the UI and logic are together) technology. Instead, it decouples the two by separating the UI from the logic. Therefore, creating a custom control generates two files, one of which is Generic. xaml, which defines its template and style; the other is <ControlName>. cs, which stores its logic, such:

In this case, to obtain the control defined in the template in the Code, it is not as easy as Code-Behind, but the OnApplyTemplate and GetTemplateChild methods must be used. Their meanings are as follows:

  • OnApplyTemplate: This method is usually rewritten in a custom control. It is called when the base class calls the ApplyTemplate () method to construct a visualization tree;
  • GetTemplateChild: gets the specified name element in the visualization tree defined in ControlTemplate;

Therefore, if we define a button named PART_ViewButton in the template, we can get it and register the RESPONSE event for it as follows:

Public override void OnApplyTemplate () {base. OnApplyTemplate (); Button btnView = GetTemplateChild ("PART_ViewButton") as Button; if (btnView! = Null) {btnView. Click + = BtnView_Click;} private void BtnView_Click (object sender, RoutedEventArgs e) {// write the response logic here}

When we (or others) use this control, the OnApplyTemplate method will be executed after a template is set for it (generally the default template. This seems okay. However, this may cause a serious problem:Memory leakage (Memory Leak).

What is memory leakage?

There are multiple types of memory leaks. Generally, it refersSome types of resources are no longer used, but still occupy the memory.. In other words, it "leaks" from the managed memory area. If there are multiple memory leaks in the program, it will occupy a lot of memory and eventually lead to memory depletion.

In C #, common memory leaks include:

• Event listening is not removed;
• Unmanaged resources (such as databases and file streams) were not destroyed );

For the above two cases, their solutions are also very simple, namely: to re-register the event (that is, to remove the event listening) and call the Dispose method (if not, implement the IDisposable interface and destroy unmanaged resources in it ).

For the second case, it is easy to understand. For the first case, the question is, why does the event listening not be removed, leading to memory leakage? This is because the event source has a longer life cycle than the event listener. Let's look at the Code:

            ObjectA objA = new ObjectA();            ObjectB objB = new ObjectB();            objA.Event += objB.EventHanlder;

The Event is defined in ObjectA, And we register an Event processor for it (EventHanlder method in object objB). Therefore, the Event source objA has a reference to the Event listening object objB.

If objB is no longer used, we will destroy it, but because objA references it, it will not be destroyed or recycled; it will not be destroyed until objA is destroyed. Therefore, the memory of the object that needs to be destroyed is leaked due to the reference of other objects.

Return to the issue of custom controls, because our custom controls may be overwritten or overwritten, this causes the OnApplyTemplate method to be executed multiple times in the lifecycle of the custom control. Therefore, we need to perform event anti-Registration for those controls that are obtained through the GetTemplateChild method and have added event processing (such as the btnView control in the above Code. These are all controls (elements) in the previous template. After Anti-registration, there is no reference relationship between the original control and the event listener (custom control, this avoids Memory leakage.

Solution

Based on our solution, we need to refactor the previous Code as follows:

Private Button btnView = null; public override void OnApplyTemplate () {base. OnApplyTemplate (); // first unregister the event if (btnView! = Null) {btnView. Click-= BtnView_Click;} btnView = GetTemplateChild ("PART_ViewButton") as Button; if (btnView! = Null) {btnView. Click + = BtnView_Click;} private void BtnView_Click (object sender, RoutedEventArgs e) {// write the response logic here}

This solves the problems mentioned at the beginning of this article. However, next, we need to make some adjustments.

Imagine if our custom control contains multiple controls similar to the aforementioned btnView, We need to copy the above Code several times in the OnApplyTemplate method, as a result, the complexity of the OnApplyTemplate method increases and the code readability deteriorates.

To improve this, we encapsulate each control and its event registration and anti-registration. The reconstructed code is as follows:

Protected const string PART_ViewButton = nameof (PART_ViewButton); private Button btnView = null; public Button ViewButton {get {return btnView;} set {// first unregister the event if (btnView! = Null) {btnView. Click-= BtnView_Click;} btnView = value; if (btnView! = Null) {btnView. click + = BtnView_Click ;}} public override void OnApplyTemplate () {base. onApplyTemplate (); ViewButton = GetTemplateChild (PART_ViewButton) as Button;} private void BtnView_Click (object sender, RoutedEventArgs e) {// write the response logic here}

For the final code, here are the following points:

1. In the OnApplyTemplate method, it is recommended that base. OnApplyTemplate () be called first ();
2. whether it is a control anti-registration event or an event registration, You must judge whether the control is empty, this is because the user may not follow the control name specified in the TemplatePart attribute when rewriting the template;
3. Declare the control name as a constant to avoid spelling errors of strings;

Summary

This article discusses the possibility of Memory leakage when creating custom controls in WPF or UWP, mainly because the control events in the template are not reversed. We have not only analyzed the causes, but also provided the best practices for this situation.

Although in general, this problem does not have a major impact, if we can pay attention to these details, this not only improves our code quality and program performance, but also provides us with the necessary ideas and experiences when designing or handling similar problems.

Related Article

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.