简体   繁体   中英

Silverlight deep copy of a UIElement using PropertyInfo's SetValue?

I have a RadComboBox from telerik which has some protected setters for a few of it's properties. I want to be able to set each and every property so I derived from that control and I have created a custom control. I also did the same thing for it's items component.

public class RadComboBoxItem : ListBoxItem
{

    ...

    public bool IsHighlighted
{
    get
    {
        return (bool)GetValue(IsHighlightedProperty);
    }
    protected set
    {
        this.SetValue(IsHighlightedPropertyKey, value);
    }
}

    ...

}

public class MyCustomComboBoxItem : RadComboBoxItem 
{
    public void HighlightItem(bool _default)
    {
        this.IsHighlighted = _default;
    }
}

In my case I have a list of RadComboBoxItems and I want to create a new list of type MyCustomComboBoxItem, so I can access the setter for each item from the first list based on the data:

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        ...

        foreach (RadComboBoxItem _item in _listOfRadComboBoxItems)
        {
            MyCustomComboBoxItem _customCBI = new MyCustomComboBoxItem();
            _customCBI.Load(_customCBI.GetType(), _item, true);
            _listOfCustomCBI.Add(_newB2);
        }
    }
}

I found another post with an explanation on what I am trying to do but my case is a little different and I borrowed the Load method from here:

Updating ObservableCollection Item properties using INotifyPropertyChanged

public static class ExtentionMethods
{
    public static void Load<T>(this T target, Type type, T source, bool deep)
    {
        foreach (PropertyInfo property in type.GetProperties())
        {
            if (property.CanWrite && property.CanRead)
            {
                if (!deep || property.PropertyType.IsPrimitive || property.PropertyType == typeof(String))
                {
                    property.SetValue(target, property.GetValue(source, null), null);
                }
                else
                {
                    object targetPropertyReference = property.GetValue(target, null);
                    targetPropertyReference.Load(targetPropertyReference.GetType(), property.GetValue(source, null), deep);
                }
            }
        }
    }
}

Recap: What I am trying to do here is create a custom ComboBox from Telerik's RadComboBox. This has ComboBoxItems that have the IsHighlighted dependency property setter protected. I created MyCustomComboBoxItem to circumvent this limitation but I can't get to copy the RadComboBoxItem into MyCustomComboBoxItem.

Reason: I want to be able to set it, so I can help the user in a better experience.

Thanks.

The IsHightlighted Property in the RadComboBoxItem is an internal property, and probably with good reason. If you try to manipulate the property for your own purposes, the results will likely be unpredictable.

At it's heart, the IsHighlighted property is simply used to trigger visual state changes. If you just want to highlight the item under a given circumstance, the best approach is to

  • Create a copy of the RadComboBoxItem ControlTemplate (using Blend is easiest for this).
  • Create a derived class (as you have already).
  • Add your own DependencyProperty (or property or method depending upon how you want to use it) and change the TargetType on the copied ControlTemplate and Style to match the DefaultStyleKey in your new class.

Now you simply need to add a new VisualStateGroup to the existing collection in the control template. The VisualStates in that group should include at least one empty (default) state and your custom highlighted state. Best practice dictates that your highlighted state should only affect properties which are not affected by other states.

For example:

<ControlTemplate TargetType="controls:MyCustomComboBox">
     <Grid x:Name="VisualRoot">
                    ...
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates" ei:ExtendedVisualStateManager.UseFluidLayout="True">
                            ...
                        <VisualStateGroup x:Name="MyHighlightStates">
                            <VisualState x:Name="NotHighlightedState" />
                            <VisualState x:Name="MyHightlightedState">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="MyHighlightElement" Storyboard.TargetProperty="Visibility">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
        <Border x:Name="MyHighlightElement" Background="Yellow" Visibility="Collapsed"/>

    ...
    </Grid>
</ControlTemplate >

Finally, you will just need to use the VisualStateManager to trigger the visual state change from a method in your control:

VisualStateManager.GoToState(this, "MyHightlightedState", true);

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