Build a simple WPF/SL binding mechanism using extension methods

Source: Internet
Author: User

In yesterday's blog, "the poor Data Binding Design for WPF/Silverlight", we analyzed the binding defects in three major application scenarios: WPF/SL. More than 95% of my applications (or even more than 99%) are bound to those three application scenarios. Therefore, the complicated binding mechanism of WPF/SL is unacceptable. It is not an aim. It is a hacker's spirit to find a solution to the problem. After knowing the defect, you can make up for it. It took just two hours to write a new WPF/SL binding mechanism using the extension method.

This article is just a simple draft and exploration of ideas, which can prove the feasibility of this mechanism. Due to recent shortage of time, we cannot provide a complete solution yet. If you are interested, you can write a more perfect extension method along the ideas in this article.

I. Simple binding requirements

Why? Since there are a lot of "simple" binding requirements, WPF/SL is not doing well. For example:

This interface has four editing statuses: None indicates that the image cannot be edited, drawregion indicates that the image is framed, drawfrontpoint indicates that the foreground is drawn on the image, and drawbackgroundpoint indicates that the background is painted on the image. Editmode is represented by enumerative editmode. editmode is stored in the editmodevalue attribute:

Public Enum editmode
{
None,
Drawregion,
Drawfrontpoint,
Drawbackgroundpoint
}

A simple requirement is to associate the editmodevalue with the status of several buttons on the right. For example, when editmodevalue is drawregion, the "Draw separated area" button is in the pressed state (isenabled is false ), other buttons are similar. When you press a button, the editmodevalue is automatically changed to a certain state,

Data Binding is the best solution to this problem. However, the data binding in WPF/SL is too weak. Writing such data binding is cumbersome and far-fetched.

Ii. New Solutions

Next we will use reflection + extension methods to write a more concise data binding solution. Go directlyCode, Less than one hundred lines of code, implementing the function of binding the property chain (not doing a full test, there may be errors, use it with caution ):

Using system;
Using system. Collections. Generic;
Using system. componentmodel;
Using system. LINQ;
Using system. text;
Using system. reflection;

Namespace Orc. util
{
Public static class bindinghelper
{
Internal class propertychangedcallback
{
Internal inotifypropertychanged caller {Get; set ;}
Internal string propertyname {Get; set ;}
Internal Action callback {Get; set ;}
Internal inotifypropertychanged SRC {Get; set ;}
Internal string path {Get; set ;}
Internal list <propertychangedcallback> callbacklist {Get; set ;}
Internal void onpropertychanged (Object sender, propertychangedeventargs E)
{
If (E. propertyname = propertyname)
{
// Remove the event to avoid side effects
If (callbacklist! = NULL)
{
Foreach (propertychangedcallback item in callbacklist)
{
If (item. caller! = NULL)
Item. Caller. propertychanged-= item. onpropertychanged;
}
Callbacklist. Clear ();
}

// Callback
Callback ();

// Add an event
Addcallback (SRC, callback, PATH );
}
}

Internal static void addcallback (inotifypropertychanged SRC, Action callback, string path)
{
If (src = NULL | callback = NULL | string. isnullorempty (PATH) return;

List List = new list ();
inotifypropertychanged current = SRC;
type = SRC. getType ();
string [] pathes = path. split ('. ');
foreach (string item in pathes)
{< br> If (current = NULL) return;

String name = item. Trim ();
If (string. isnullorempty (name) break;

Propertychangedcallback c = new propertychangedcallback ();
C. Callback = callback;
C. Caller = current;
C. src = SRC;
C. propertyname = Name;
C. callbacklist = List;
C. Path = path;
Current. propertychanged + = C. onpropertychanged;
List. Add (C );

Propertyinfo Pi = type. getproperty (name );
If (Pi = NULL) break;

Object P = pi. getvalue (current, null );
Inotifypropertychanged Np = P as inotifypropertychanged;
If (Np = NULL) break;

current = NP;
type = NP. GetType ();
}< BR >}

Public static void setbindingchain (this object DST, inotifypropertychanged SRC, string path, Action callback)
{
If (src = NULL | callback = NULL | string. isnullorempty (PATH) return;
Propertychangedcallback. addcallback (SRC, callback, PATH );
}
}
}

Setbindingchain is the extension method used for binding. SRC is the binding source, and path is the binding attribute chain. The syntax is similar to the property call syntax (a. B .c.d). You can copy it after writing the prompt in IDE, callback is a callback event when the attribute changes. It can be a Lambda expression. It is best to Perform Batch binding during form load or an event.

You can also write out the multi-attribute chain binding and multi-object binding extension methods based on this idea. This article will not write down. The following is a prototype:

Public static void setbindingchain (this object DST, inotifypropertychanged SRC, string [] pathes, Action callback)
{
Throw new notimplementedexception ();
}

Public static void setbindingchain (this object DST, inotifypropertychanged src1, string path1, inotifypropertychanged src2, string path2, Action callback)
{
Throw new notimplementedexception ();
}

Public static void setbindingchain (this object DST, inotifypropertychanged src1, string [] pathes1, inotifypropertychanged src2, string [] pathes2, Action callback)
{
Throw new notimplementedexception ();
}

Public static void setbindingchain (this object DST, inotifypropertychanged src1, string path1, inotifypropertychanged src2, string path2, inotifypropertychanged src3, string path3, Action callback)
{
Throw new notimplementedexception ();
}

Public static void setbindingchain (this object DST, inotifypropertychanged src1, string [] pathes1, inotifypropertychanged src2, string [] pathes2, inotifypropertychanged src3, string [] pathes3, Action callback)
{
Throw new notimplementedexception ();
}

Public static void setbindingchain (this object DST, inotifypropertychanged src1, string path1, inotifypropertychanged src2, string path2, inotifypropertychanged src3, string path3, inotifypropertychanged src4, string path4, Action callback)
{
Throw new notimplementedexception ();
}

Public static void setbindingchain (this object DST, inotifypropertychanged src1, string [] pathes1, inotifypropertychanged src2, string [] pathes2, inotifypropertychanged src3, string [] pathes3, inotifypropertychanged src4, string [] pathes4, Action callback)
{
Throw new notimplementedexception ();
}

3. Use the new solution for data binding

Editmodevalue attributes:

Private editmode m_editmodevalue = editmode. None;

Public editmode editmodevalue
{
Get {return m_editmodevalue ;}
Set {
If (m_editmodevalue = value) return;
M_editmodevalue = value;
Notifypropertychanged ("editmodevalue ");
}
}

One-way binding:

This. setbindingchain (this, "editmodevalue ",
() =>
{
Btndrawsegregion. isenabled = editmodevalue! = Editmode. drawregion;
Btndrawfpoints. isenabled = editmodevalue! = Editmode. drawfrontpoint;
Btndrawbpoints. isenabled = editmodevalue! = Editmode. drawbackgroundpoint;
});

Then the status changes when the button is pressed:

Private void btndrawsegregion_click (Object sender, routedeventargs E)
{
Editmodevalue = editmode. drawregion;
}

Private void btndrawfpoints_click (Object sender, routedeventargs E)
{
Editmodevalue = editmode. drawfrontpoint;
}

Private void btndrawbpoints_click (Object sender, routedeventargs E)
{
Editmodevalue = editmode. drawbackgroundpoint;
}

Done!

Iv. Analysis

Using the extension method setbindingchain can simplify the first two scenarios mentioned in the "poor Data Binding Design for WPF/Silverlight", which is much easier to use and has no learning cost, it can meet most of the binding requirements. The user experience is similar to the flex binding solution. There are also some differences:

(1) binding is written in the background, without being intuitive at the front end, and decoupling is not convenient;

(2) Flex is an automatic analysis of the binding chain, and manual input of the binding chain here is a big pity;

Despite this, it is much better than the hard-to-learn and difficult-to-use WPF/SL source binding. It is concise, clear, does not need to learn, does not need to remember, flexible, suitable for most application scenarios. This article only binds the property chain. If you have other requirements, such as binding the indexer, please expand it on your own.

As for the third scenario, there is no good solution yet.

V. Others

I like simple and clear solutions. For example, to enable the image function on the Interface above, my code is:

Private void btnopen_click (Object sender, routedeventargs E)
{
This. openimagefile (string path) => {
Tbimgpath. Text = path;
Editmodevalue = editmode. None;
});
}

It is very simple and clear. You do not need to drag openfiledialog out or remember the filter syntax. Of course, there is an extension method behind it to provide services silently:

Public static void openimagefile (this window element, Action callbackonfilepath, string filter = "Image File | *. BMP ;*. JPG ;*. GIF ;*. PNG ")
{< br> string filepath;
openfiledialog DLG = new openfiledialog ();

DLG. filter = filter;
DLG. fileok + = (Object sender, canceleventargs e) =>
{< br> filepath = DLG. filename;
If (callbackonfilepath! = NULL)
callbackonfilepath (filepath);
};
DLG. showdialog ();
}

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.