Solution: easy 'PreventNesingAttribute' implementation for separate properties

1 posts, 0 answers
  1. Art
    Art avatar
    33 posts
    Member since:
    Apr 2015

    Posted 19 Feb 2017 Link to this post

    Hello! I found this discussion. 08 Oct 2014 Yoan says:

    "I am afraid that this functionality is not supported since there are some conceptual impediments that prevent us to change the implementation of RadPropertyGrid. However, I have logged this in our system as feature request..."

    Anyway, I spent a couple of hours and just put it here. All we need is:

    1. ControlTemplate of the PropertyGridFieldTemplate, defined in ResourceDictionary (Theme);
    2. NestedPropertyVisibilityBehavior
    3. PreventNestingAttribute

    In the ControlTemplate find "PART_NestedPropertiesButton" and replace it with

    <t:RadToggleButton x:Name="PART_NestedPropertiesButton"
            Style="{StaticResource PropertyGridNestedToggleButtonStyle}"
            Background="Transparent"
            Width="25"
            IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsExpanded, Mode=TwoWay}">
        <i:Interaction.Behaviors>
            <behaviors:NestedPropertyVisibilityBehavior PropertyGridField="{Binding RelativeSource={RelativeSource TemplatedParent}}"
     ShouldDisplayNestedProperties="{Binding ShouldDisplayNestedProperties, RelativeSource={RelativeSource TemplatedParent}}"/>
        </i:Interaction.Behaviors>
    </t:RadToggleButton>

     

    Behavior class:

    public class NestedPropertyVisibilityBehavior : Behavior<RadToggleButton>
    {
        public static readonly DependencyProperty PropertyGridFieldProperty =
            DependencyProperty.Register("PropertyGridField", typeof (PropertyGridField),
                typeof (NestedPropertyVisibilityBehavior), new PropertyMetadata(null, OnPropertyGridFieldChanged));
     
        public static readonly DependencyProperty ShouldDisplayNestedPropertiesProperty =
            DependencyProperty.Register("ShouldDisplayNestedProperties", typeof (bool),
                typeof (NestedPropertyVisibilityBehavior), new PropertyMetadata(false, OnShouldDisplayNestedPropertiesChanged));
     
        private bool _preventNesting;
     
        public PropertyGridField PropertyGridField
        {
            get { return (PropertyGridField)GetValue(PropertyGridFieldProperty); }
            set { SetValue(PropertyGridFieldProperty, value); }
        }
     
        public bool ShouldDisplayNestedProperties
        {
            get { return (bool)GetValue(ShouldDisplayNestedPropertiesProperty); }
            set { SetValue(ShouldDisplayNestedPropertiesProperty, value); }
        }
     
        private static void OnShouldDisplayNestedPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = (NestedPropertyVisibilityBehavior) d;
            sender.UpdateVisibility();
        }
     
        private static void OnPropertyGridFieldChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var field = e.NewValue as PropertyGridField;
     
            if (field == null)
                return;
     
            var propDef = field.DataContext as PropertyDefinition;
     
            if (propDef == null)
                return;
     
            var attrs = GetCustomAttributes(propDef.Instance, propDef.SourceProperty.Name);
            var sender = (NestedPropertyVisibilityBehavior) d;
     
            sender._preventNesting =  attrs.Any(x => x is PreventNestingAttribute);
            sender.UpdateVisibility();
        }
     
        protected override void OnAttached()
        {
            UpdateVisibility();
        }
     
        private void UpdateVisibility()
        {
            if (AssociatedObject == null)
                return;
     
            AssociatedObject.Visibility = ShouldDisplayNestedProperties && !_preventNesting
                ? Visibility.Visible
                : Visibility.Collapsed;
        }
     
        protected static object[] GetCustomAttributes(object source, string propertyPath)
        {
            if (source == null || string.IsNullOrEmpty(propertyPath))
                return null;
     
            PropertyInfo propertyInfo = null;
     
            var currentType = source.GetType();
            var path = propertyPath.Split('.');
     
            for (int i = 0, count = path.Length; i < count; i++)
            {
                var propertyStep = path[i];
                propertyInfo = currentType.GetProperty(propertyStep);
     
                if (propertyInfo == null || source == null || i == count - 1)
                    break;
     
                source = propertyInfo.GetValue(source, null);
                currentType = propertyInfo.PropertyType;
            }
     
            return propertyInfo != null ? propertyInfo.GetCustomAttributes(true) : null;
        }
    }

     

    Attribute:

    [AttributeUsage(AttributeTargets.Property)]
    public sealed class PreventNestingAttribute : Attribute { }

     

    Usage in your Settings item:

    [PreventNesting]
    //[Display(Name = "Margin")]
    public Thickness Margin
    {
        get
        {
            return _margin;
        }
     
        set { Set(() => Margin, ref _margin, value); }
    }

     

    I would be happy if it can be made more compact. I made it in haste.

     

    Microsoft Silverlight (64-bit) Version: 5.1.41105.0
    Windows 8.1 (64-bit)
    Internet Explorer 11.0.9600.17416
    Telerik 2017.1.117.1050

Back to Top