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,
- public BindingExpression SetBinding(
- DependencyProperty dp,
- string path
- )
First I created a class that would store the information I need. I also store the propertyinfo
- public class UIControledElement
- {
-
- public FrameworkElement Element { get; set; }
-
- public DependencyProperty LanguageProperty { get; set; }
-
- public PropertyInfo UiModelProperty { get; set; }
- }
The Base model is a bit more complex
- public class UIModel<TWindow> where TWindow : Window
- {
-
- private static TWindow context;
-
- private static List<UIControledElement> UIControledElements = new List<UIControledElement>();
-
- public UIModel(TWindow context)
- {
- UIModel<TWindow>.context = context;
- UIModel<TWindow>.context.ContentRendered += Context_ContentRendered;
- }
-
- private void Context_ContentRendered(object sender, EventArgs e)
- {
- this.UpdateDisplay();
- }
-
-
- protected static UIControledElement Register
- (string PropertyInfo, DependencyProperty Property, Type Owner) {
- var propertyInfo =
- Owner.GetProperty(PropertyInfo, BindingFlags.Public | BindingFlags.Instance);
-
- if (propertyInfo != null) {
- var uicontroled = new UIControledElement { UiModelProperty = propertyInfo, LanguageProperty = Property };
- UIModel<TWindow>.UIControledElements.Add(uicontroled);
- return uicontroled;
- }
- return null;
- }
-
- protected FrameworkElement GetValue(UIControledElement Element)
- { return Element.Element; }
-
- protected void SetValue(UIControledElement Element, FrameworkElement Value)
- {Element.Element = Value;}
-
-
- private void UpdateDisplay()
- {
- foreach (var item in UIModel<TWindow>.UIControledElements)
- {
- DisplayAttribute Attribute =
- item.UiModelProperty.GetCustomAttribute(typeof(DisplayAttribute))
- as DisplayAttribute;
-
- if (Attribute == null) return;
-
- SetProperty(item.Element, item.LanguageProperty, Attribute.Name);
- }
- }
-
-
- private void SetProperty(FrameworkElement Element, DependencyProperty Property, object value) {
- Type depencendyObjectType = typeof(DependencyObject);
-
- MethodInfo SetValueMethodInfo =
- depencendyObjectType.GetMethod("SetValue",
- new Type[] { typeof(DependencyProperty), typeof(object) });
-
- SetValueMethodInfo.Invoke(Element, new object[] { Property, value });
- }
-
- }
So far we made the infrastructure. Now we make our class
- public class UINumberModel: UIModel < MainWindow >
- {
- private static UIControledElement exampleText = Register("ExampleText", Label.ContentProperty, typeof(UINumberModel));
- [Display(Name = "Bla Bla")]
- public FrameworkElement ExampleText {
- get {
- return GetValue(exampleText);
- }
- set {
- SetValue(exampleText, value);
- }
- }
- public UINumberModel(MainWindow context): base(context) {}
- }
Usage
- public MainWindow()
- {
- InitializeComponent();
- UINumberModel m = new UINumberModel(this) { ExampleText = LabelIO };
- }
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.