Using UIModel Class For Binding In WPF

When creating WPF applications, you use binding. It’s a very nice workflow except for one point, where I want to bing the ContentProperty of a Label or a TextBlock. If I set this up in the xaml code with {Binding}, then I don’t have the “feeling” of the designer since there is no text until it compiles.

You can use “SetBinding” method for this programmatically in code, and having this in mind I decided that I need an UIModel class that encapsulates the logic of it.

The usage of SetBinding is,

  1. public BindingExpression SetBinding(  
  2.     DependencyProperty dp,  
  3.     string path  
  4. )  

First I created a class that would store the information I need. I also store the propertyinfo

  1. public class UIControledElement  
  2.   {  
  3.       //ui element from the window  
  4.       public FrameworkElement Element { get; set; }  
  5.       //dependency property to affect. Set in the attribute in the class  
  6.       public DependencyProperty LanguageProperty { get; set; }  
  7.       //property info  
  8.       public PropertyInfo UiModelProperty { get; set; }  
  9.   }  

The Base model is a bit more complex

  1. public class UIModel<TWindow> where TWindow : Window  
  2.     {  
  3.         //I need the context which is the MainWindow to get the tagged properties  
  4.         private static TWindow context;  
  5.         //Because the register method below is static, this element is also static  
  6.         private static List<UIControledElement> UIControledElements = new List<UIControledElement>();  
  7.   
  8.         public UIModel(TWindow context)  
  9.         {  
  10.             UIModel<TWindow>.context = context;  
  11.             UIModel<TWindow>.context.ContentRendered += Context_ContentRendered;  
  12.         }  
  13.         //Making sure that all elements are loaded and rendered, afterwards we make the changes required  
  14.         private void Context_ContentRendered(object sender, EventArgs e)  
  15.         {  
  16.             this.UpdateDisplay();  
  17.         }  
  18.         //this method is called in the child class to register a property. Because at this point the object doesn;t exist  
  19.         //we need to call it statically. In here we also store the DependencyProperty that we will alter  
  20.         protected static UIControledElement Register  
  21. (string PropertyInfo, DependencyProperty Property, Type Owner) {  
  22.             var propertyInfo =   
  23. Owner.GetProperty(PropertyInfo, BindingFlags.Public | BindingFlags.Instance);  
  24.   
  25. if (propertyInfo != null) {  
  26.    var uicontroled = new UIControledElement { UiModelProperty = propertyInfo, LanguageProperty = Property };  
  27.    UIModel<TWindow>.UIControledElements.Add(uicontroled);  
  28.    return uicontroled;  
  29.             }  
  30.             return null;  
  31.         }  
  32.         //this method returns the UIElement  
  33.         protected FrameworkElement GetValue(UIControledElement Element)   
  34. return Element.Element; }  
  35.         //this methods sets the UIElement  
  36.         protected void SetValue(UIControledElement Element, FrameworkElement Value)   
  37. {Element.Element = Value;}  
  38.   
  39.         //in this method we get the value from the attribute and call the function SetProperty  
  40.         private void UpdateDisplay()  
  41.         {  
  42.             foreach (var item in UIModel<TWindow>.UIControledElements)  
  43.             {  
  44. DisplayAttribute Attribute =   
  45. item.UiModelProperty.GetCustomAttribute(typeof(DisplayAttribute))  
  46. as DisplayAttribute;  
  47.   
  48.                 if (Attribute == nullreturn;  
  49.   
  50.                 SetProperty(item.Element, item.LanguageProperty, Attribute.Name);  
  51.             }  
  52.         }  
  53.   
  54.         //this method alters the DependencyProperty of the UIElement with the value from an attribute  
  55.         private void SetProperty(FrameworkElement Element, DependencyProperty Property, object value) {  
  56.             Type depencendyObjectType = typeof(DependencyObject);  
  57.   
  58.             MethodInfo SetValueMethodInfo =  
  59.                 depencendyObjectType.GetMethod("SetValue",   
  60. new Type[] { typeof(DependencyProperty), typeof(object) });  
  61.   
  62.             SetValueMethodInfo.Invoke(Element, new object[] { Property, value });  
  63.         }  
  64.           
  65.     }  

So far we made the infrastructure. Now we make our class

  1. public class UINumberModel: UIModel < MainWindow >   
  2.   {  
  3.     private static UIControledElement exampleText = Register("ExampleText", Label.ContentProperty, typeof(UINumberModel));  
  4.     [Display(Name = "Bla Bla")]  
  5.     public FrameworkElement ExampleText {  
  6.         get {  
  7.             return GetValue(exampleText);  
  8.         }  
  9.         set {  
  10.             SetValue(exampleText, value);  
  11.         }  
  12.     }  
  13.     public UINumberModel(MainWindow context): base(context) {}  
  14. }  

Usage

  1. public MainWindow()  
  2.         {  
  3.             InitializeComponent();  
  4.             UINumberModel m = new UINumberModel(this) { ExampleText = LabelIO };  
  5.         }  

When not compiled, Label will have a content, when compiled it will take the attribute and replace the content. The attribute can also be linked to a Language.Res file.

Next Recommended Reading WPF Binding One Way and Two Way