简体   繁体   中英

Get control from property name in viewmodel using Caliburn Micro

I want to get a reference to the TextBox bound to a given property name. I would like to do this without changing the view. Is there a proper way to do this using Caliburn Micro? If not, what is a "good enough" way?

public class MweViewModel : PropertyChangedBase
{
    public MweViewModel() : base()
    {
        PropertyChanged += (object sender, PropertyChangedEventArgs e) =>
        {
            // Find control (i.e. TextBox) bound to property with name e.PropertyName
            TextBox textBox = ...
        };
    }
}

I'm not necessarily sure this is the most sensible approach (it's not something I've tried to do myself), looking at the Documentation , there's the mention of a ViewModelBinder class that's responsible for fixing up the various bindings of properties, methods, etc. to their respective ViewModels .

The BindProperties function on the ViewModelBinder is responsible for resolving the bindings between your properties, and the UI elements to which they're eventually bound. You could, define your own function based on the existing code, which kept track of all the bindings being established, so you would have a record of them you could use elsewhere in your program.

Using the existing code would give you something like this:

ViewModelBinder.BindProperties = (namedElements, viewModelType) =>
    {
        var unmatchedElements = new List<FrameworkElement>();

        foreach (var element in namedElements)
        {
            var cleanName = element.Name.Trim('_');
            var parts = cleanName.Split(new[] { '_' }, StringSplitOptions.RemoveEmptyEntries);

            var property = viewModelType.GetPropertyCaseInsensitive(parts[0]);
            var interpretedViewModelType = viewModelType;

            for (int i = 1; i < parts.Length && property != null; i++)
            {
                interpretedViewModelType = property.PropertyType;
                property = interpretedViewModelType.GetPropertyCaseInsensitive(parts[i]);
            }

            if (property == null)
            {
                unmatchedElements.Add(element);
                // Log.Info("Binding Convention Not Applied: Element {0} did not match a property.", element.Name);
                continue;
            }

            var convention = ConventionManager.GetElementConvention(element.GetType());
            if (convention == null)
            {
                unmatchedElements.Add(element);
                // Log.Warn("Binding Convention Not Applied: No conventions configured for {0}.", element.GetType());
                continue;
            }

            var applied = convention.ApplyBinding(
                interpretedViewModelType,
                cleanName.Replace('_', '.'),
                property,
                element,
                convention
                );

            if (applied)
            {
                // Log.Info("Binding Convention Applied: Element {0}.", element.Name);
            }
            else
            {
                // Log.Info("Binding Convention Not Applied: Element {0} has existing binding.", element.Name);
                unmatchedElements.Add(element);
            }
        }

        return unmatchedElements;
    };

At the point when the binding is being added (when applied is set), you have all the information you require. You could then store specific bindings (eg those relating to a TextBox ).

You might use something like a static dictionary (there may be something far more appropriate depending on your requirement):

        ViewModel Type    Bound Property      List of Bound elements
             |                   |                      |
             |                   |                      |
Dictionary<Type, Dictionary<PropertyInfo, List<FrameworkElement>>>

You would have to be careful about null/sanity checks.

There are a few other solutions that use helper methods to grab the bound properties/controls, although they often have to traverse the visual tree, this way, you're doing it at the point the binding is actually created.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM