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

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.