Adding a convention for IsEnabled to Caliburn.Micro
Asked Answered
A

2

6

How do I add a custom convention to Caliburn.Micro for the IsEnabled property of controls - something like having NameEnabled bound to IsEnabled in parallel to Name bound to Text on a TextBox.

In a way, what I want to achieve is similar to the way that a CanSave property can be used to enable/disable a button bound to a Save method, but generic for all controls.

Alexandros answered 28/1, 2012 at 8:52 Comment(0)
D
14

Caliburn.Micro right now (1.3.1) doesn't really support this "multiple" conventions for the same FrameworkElement, what you have described.

EDIT:

However you can hook into the ViewModelBinder.BindProperties method and there you can implement your own extra convetion.

I went one step further and implemented a prototype which works, but it's not robust, nor elegant and probably not the correct way to do this. But it can be a starting point:

static AppBootstrapper()
{
    ConventionManager.AddElementConvention<FrameworkElement>(
         UIElement.IsEnabledProperty, 
         "IsEnabled", 
         "IsEnabledChanged");
    var baseBindProperties = ViewModelBinder.BindProperties;
    ViewModelBinder.BindProperties =
        (frameWorkElements, viewModels) =>
        {
            foreach (var frameworkElement in frameWorkElements)
            {
                var propertyName = frameworkElement.Name + "Enabled";
                var property = viewModels
                     .GetPropertyCaseInsensitive(propertyName);
                if (property != null)
                {
                    var convention = ConventionManager
                        .GetElementConvention(typeof(FrameworkElement));
                    ConventionManager.SetBindingWithoutBindingOverwrite(
                        viewModels,
                        propertyName,
                        property,
                        frameworkElement,
                        convention,                                          
                        convention.GetBindableProperty(frameworkElement));
                }
            }
            return baseBindProperties(frameWorkElements, viewModels);
       };
}
Decennary answered 28/1, 2012 at 16:9 Comment(8)
Seems like a relatively painless way to achieve the end result I want - though I'm really suprised that Caliburn Micro doesn't have explicit support for this kind of thing, as having bindings for IsEnabled and IsReadOnly is pretty common in a UI. [I assumed my GoogleFu was at fault when I couldn't find an answer myself.]Alexandros
I've updated my solution because the original one killed the default conventions :) Now it works also with your sample <TextBox Name="Name" /> Bindings: Text-> Property: Name and IsEnabled -> Property NameEnabled.Decennary
@juanagui thanks for the update. I didn't know that the API changed with version 1.3.1Decennary
@nemesv, np, and thanks for the snippet, it was really helpfulOkra
@Decennary how did you change the code to enable it to work with existing conventions? Did you change the elementType to FrameworkElement so it didn't conflict with existing TextBox conventions? I've just tried this code replacing FrameworkElement with TextBox and it breaks default CM Text convention. I'd like to use your solution but notice CM also has a default convention for FrameworkElement (DataContext) that I'm loathed to break.Ursulaursulette
@Decennary Is this solution up to date or have similar functionality been added to the framework?Dendritic
@Dendritic I'm not really into Caliburn.Micro anymore... but having a quick look on the source code on github it seems nothing has changed this regard...Decennary
This still works for Caliburn Micro v3.2.0 as of 20 Oct 2019. I just pasted the above code into public Bootstrapper() after the Initialize(); and managed to get my buttons in the View to enable and disable by setting NameEnabled in the ViewModel. Thanks.Dromedary
B
-2

You can enable/disable a control by setting a boolean property in your ViewModel and you just bind to IsEnabled in XAML:

TextBox  Name="SerialNumber" IsEnabled="{Binding IsReadOnly}"...

ViewModel:
   private bool isReadOnly;
    public bool IsReadOnly
    {
        get { return isReadOnly; }
        set
        {
            this.isReadOnly = value;
            NotifyOfPropertyChange( () => IsReadOnly);
        }
    }
Bowser answered 30/5, 2013 at 9:47 Comment(1)
Sure, but if I wanted to manually set up all my binding I wouldn't be using Caliburn.Micro in the first place.Alexandros

© 2022 - 2024 — McMap. All rights reserved.