mardi 23 août 2016

Set DependncyProperty from reflection in wpf - type convertion

I have some fun with WPF and I decided to build a library with custom implementation of attached triggers (similar to System.Windows.Interactivity.dll), but my own. I have a class TriggerAction which represents an action invoked by Trigger. I want to begin with something really easy like setting the background of the button while the user click it. I have already written some working code for example EventTrigger class, but I have one problem with my SetterTriggerAction. I have two dependency properties PropertyName which represents the name of property which should be set an a Value property. In the Invoke method I try to set property with a defined value. Here is the code:

internal override void Invoke(DependencyObject obj)
    {
        if (obj == null) return;
        if (string.IsNullOrEmpty(PropertyName)) return;
        PropertyInfo property = obj.GetType().GetProperty(PropertyName, BindingFlags.Public | BindingFlags.Instance);
        if (property == null)
        {
            Debug.WriteLine("Cannot find property {0} for type {1}.", PropertyName, obj.GetType());
            return;
        }
        MethodInfo setMethod = property.GetSetMethod();
        if (setMethod == null)
        {
            Debug.WriteLine("The property {0} does not have set method.", PropertyName);
            return;
        }
        try
        {
            setMethod.Invoke(obj, new object[] { Value });
        }
        catch(Exception ex)
        {
            Debug.WriteLine("Exception caught {0} with message {1}", ex.GetType(), ex.Message);
        }
    }

My second attempt:

internal override void Invoke(DependencyObject obj)
    {
        if (obj == null) return;
        if (string.IsNullOrEmpty(PropertyName)) return;
        FieldInfo property = obj.GetType().GetField(PropertyName+"Property", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
        if (property == null)
        {
            Debug.WriteLine("Cannot find dependency property {0} for type {1}.", PropertyName+"Property", obj.GetType());
            return;
        }
        try
        {
            DependencyProperty dp = property.GetValue(obj) as DependencyProperty;
            if(dp == null)
            {
                Debug.WriteLine("Cannot get DependencyProperty {0}", PropertyName + "Property");
                return;
            }
            obj.SetValue(dp, Value);
        }
        catch(Exception ex)
        {
            Debug.WriteLine("Exception caught {0} with message {1}", ex.GetType(), ex.Message);
        }
    }

In xaml I wrote:

<Button HorizontalAlignment="Center" VerticalAlignment="Center" Content="Click">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <i:SetterTriggerAction PropertyName="Background" Value="Red"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>

So when I click the button I want to make its background red. However both versions of Invoke method suffers from convertion issue and in my output window I get a message that "Red" is not valid value for property Background (because it is treated like string not a Brush!). Is there any way to convert a value from xaml (string "Red") to a valid Brush value? I would like to have as general way of converting properties as possible.

I consider that something similar to what I want to achieve is done when xaml is parsed and properties of controls are set.

Any help would be appreciated.





Aucun commentaire:

Enregistrer un commentaire