PropertyGrid not displaying value on List of poco's

13 posts, 0 answers
  1. David
    David avatar
    7 posts
    Member since:
    Nov 2013

    Posted 27 Nov 2013 Link to this post

    I think I've seen this problem before, but none had a documented resolution.  I have a list of objects from the database that I want to display in a property grid.  The tables and view have been built to provide all that I need for the property grid.  Here is the poco def:

    public class Setting

    {

    public string ParameterName { get; set; }

    public string ParameterValue { get; set; }

    public string DataTypeName { get; set; }

    public string ParameterTypeName { get; set; }

    public string Description { get; set; }

    }

    I am trying it in code behind first, so my xaml is simple:

    <telerik:RadPropertyGrid x:Name="_propertyGrid" AutoGeneratePropertyDefinitions="False" />

    and the code-behind gets the list of Setting instances from the view model and wraps a PropertyDefinition around it.  It adds that PropertyDefinition to the property grid, then binds the property grid to the entire list:

    List<Setting> settings = viewModel.Settings;

    foreach (Setting setting in settings)

    {

    _propertyGrid.PropertyDefinitions.Add(new PropertyDefinition(/*new ItemPropertyInfo(setting.ParameterName, Type.GetType(setting.DataTypeName), setting.Description)*/)

    {

     Binding = new Binding("ParameterValue") { Mode = BindingMode.TwoWay /*, Path = new PropertyPath("ParameterValue")*/ },

     

     Description = setting.Description,

     DisplayName = setting.ParameterName,

     GroupName = setting.ParameterTypeName,

    });

    }

    _propertyGrid.Item = settings;

     

    This works perfectly in some ways: every instance gets a row in the grid; and the DisplayName, Description, and GroupName all match the poco from whence it came.

    However, I cannot get the ParameterValue to display.  I know it is set because I can set DisplayName or Description to setting.ParameterValue and the actual value shows in the name or description, but never in the bound data.

    I look at my output window and get no binding errors.  However I get no errors even if I intentionally misspell the ParameterValue property's name, so I don't think that is conclusive.

     

    The commented out code is stuff I've tried that either generates a runtime error (new ItemPropertyInfo), or has no effect (new PropertyPath). Both seem interesting though, so I left them in for exploration.

    So my question is, can I bind the value of a property grid to a specific property of a poco in a list of them, as I can bind things like Description, DisplayName and GroupName?

    Thank you very much for your time on this.

     
    Edit: Somebody else commented in another post that it works if PropertySetMode is set to None, so I added this:

    _propertyGrid.PropertySetMode = PropertySetOperation.None;

    with no effect.  However, if I set to to Union or Intersection, the *GroupName* (not the value, but the category) shows up in the data.  How is that possible?

  2. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 28 Nov 2013 Link to this post

    Hi,

    Your setup seems to be correct.
    Would you please ensure that there is a value for the ParameterValue property? What is the result if you set the Binding to the Description property instead?

    Regards,
    Didie
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  3. UI for WPF is Visual Studio 2017 Ready
  4. David
    David avatar
    7 posts
    Member since:
    Nov 2013

    Posted 03 Dec 2013 Link to this post

    Thank you so much for your reply.

    1. Yes, there definitely is a value for the ParameterValue property.
     a. I can see it in the debugger.
     b. When I bind (?) something else to it, such as Description, the value indeed shows up where the description should go.

    2. If I set the Binding to anything else, I get the same behavior -- no value displayed in the grid, just names, categories and descriptions.

    Thank you again for your assistance here.
    Dave
  5. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 04 Dec 2013 Link to this post

    Hi Dave,

    Would it be possible for you to isolate the issue in a demo project? That way I can check it locally and advise you further.

    Regards,
    Didie
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  6. David
    David avatar
    7 posts
    Member since:
    Nov 2013

    Posted 04 Dec 2013 Link to this post

    Thank you Didi, but I have been able to come upon a solution.  Instead of:

    Binding = new Binding { Source = setting.ParameterValue },


    I am setting the Binding with this:

    Binding = new Binding { Source = setting, Path = new PropertyPath("ParameterValue") },


    and all is working well.

    I do have an issue setting this in xaml, I believe because PropertyDefinitions is not a Bindable property.  Is this true, and do you plan to change that at some point?  

    Thank you again,
    Dave
  7. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 05 Dec 2013 Link to this post

    Hi Dave,

    You should be able to set the binding of the PropertyDefinition in Xaml, specifying a Path and Source for it.

    Would you please share the exact code you use in Xaml?

    Regards,
    Didie
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  8. David
    David avatar
    7 posts
    Member since:
    Nov 2013

    Posted 05 Dec 2013 Link to this post

    Thank you Didi.  Here is the xaml that I *have* gotten to work:

      <telerik:RadPropertyGrid x:Name="_propertyGrid"
    AutoGeneratePropertyDefinitions="False"
    IsGrouped="True"><BR>   <i:Interaction.Behaviors><BR>               
    <Behaviors:PropertyGridDefinitionBindingBehavior PropertyItems="{Binding
    PosSettings}" DescriptionPath="Description" DisplayNamePath="ParameterName"
    GroupNamePath="ParameterTypeName" ValuePath="ConvertedParameterValue"
    /><BR>   </i:Interaction.Behaviors><BR>       
    </telerik:RadPropertyGrid>

    and here is the PropertyGridDefinitionBindingBehavior  class:

    public class PropertyGridDefinitionBindingBehavior : Behavior<RadPropertyGrid>
    {
        public PropertyGridDefinitionBindingBehavior()
        {
     
        }
     
     
        protected override void OnAttached()
        {
            base.OnAttached();
            Initialize();
        }
     
        private void Initialize()
        {
     
            //this.DataContext = viewModel;
            //InitializeComponent();
            if (AssociatedObject == null)
            {
                return;
            }
     
            AssociatedObject.PropertyDefinitions.Clear();
            var propertyItemsList = PropertyItems as IEnumerable<object>;
            foreach (var setting in propertyItemsList)
            {
     
                var newDefinition = new PropertyDefinition(/*new ItemPropertyInfo(setting.ParameterName, Type.GetType(setting.DataTypeName), setting.Description)*/)
                {
                    Binding = new Binding { Source = setting, Mode = BindingMode.TwoWay, Path = new PropertyPath(ValuePath) },
                };
                 
                BindingOperations.SetBinding(newDefinition, PropertyDefinition.DescriptionProperty, new Binding { Source = setting, Mode = BindingMode.TwoWay, Path = new PropertyPath(DescriptionPath) });
                BindingOperations.SetBinding(newDefinition, PropertyDefinition.DisplayNameProperty, new Binding { Source = setting, Mode = BindingMode.TwoWay, Path = new PropertyPath(DisplayNamePath) });
                BindingOperations.SetBinding(newDefinition, PropertyDefinition.GroupNameProperty, new Binding { Source = setting, Mode = BindingMode.TwoWay, Path = new PropertyPath(GroupNamePath) });
     
                AssociatedObject.PropertyDefinitions.Add(newDefinition);
            }
            // Different values here _propertyGrid.PropertySetMode = PropertySetOperation.Union;
            AssociatedObject.Item = PropertyItems;
        }
     
        public object PropertyItems
        {
            get { return (object)GetValue(PropertyItemsProperty); }
            set { SetValue(PropertyItemsProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for PropertyItems.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PropertyItemsProperty =
            DependencyProperty.Register("PropertyItems", typeof(object), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(null, (s, a) =>
            {
                var me = s as PropertyGridDefinitionBindingBehavior;
                var oldValue = a.OldValue as ObservableCollection<object>;
                if (oldValue != null)
                {
                    oldValue.CollectionChanged -= me.ItemsCollectionChanged;
                }
     
                var newValue = a.NewValue as ObservableCollection<object>;
                if (newValue != null)
                {
                    newValue.CollectionChanged += me.ItemsCollectionChanged;
                }
                me.Initialize();
            }));
     
        private void ItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            Initialize();
        }
     
        public string ValuePath
        {
            get { return (string)GetValue(ValuePathProperty); }
            set { SetValue(ValuePathProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for ValuePath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValuePathProperty =
            DependencyProperty.Register("ValuePath", typeof(string), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(string.Empty));
     
        public string DescriptionPath
        {
            get { return (string)GetValue(DescriptionPathProperty); }
            set { SetValue(DescriptionPathProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for DescriptionPath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DescriptionPathProperty =
            DependencyProperty.Register("DescriptionPath", typeof(string), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(string.Empty));
     
        public string DisplayNamePath
        {
            get { return (string)GetValue(DisplayNamePathProperty); }
            set { SetValue(DisplayNamePathProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for DisplayNamePath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisplayNamePathProperty =
            DependencyProperty.Register("DisplayNamePath", typeof(string), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(string.Empty));
     
        public string GroupNamePath
        {
            get { return (string)GetValue(GroupNamePathProperty); }
            set { SetValue(GroupNamePathProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for GroupNamePath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty GroupNamePathProperty =
            DependencyProperty.Register("GroupNamePath", typeof(string), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(string.Empty));
     
        public Type DataTypePath
        {
            get { return (Type)GetValue(DataTypePathProperty); }
            set { SetValue(DataTypePathProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for DataTypePath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataTypePathProperty =
            DependencyProperty.Register("DataTypePath", typeof(Type), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(typeof(object)));
     
    }

    With the above code, I am able to set the property name, description, category and value for each specific record from the database.  I am doing it with a behavior rather than the xaml.cs code behind.

    This actually works, but each value has a different property type, stored in the table so I know it's CLR name, but whatever I do each property is displayed and edited as a string. Is there any way to set the property type for each property, from each row in the database?

    Thank you again,
    Dave

  9. David
    David avatar
    7 posts
    Member since:
    Nov 2013

    Posted 05 Dec 2013 Link to this post

    Thank you Didi.  Here is the xaml that I *have* gotten to work:

      <telerik:RadPropertyGrid x:Name="_propertyGrid" AutoGeneratePropertyDefinitions="False" IsGrouped="True">
         <i:Interaction.Behaviors>
                    <Behaviors:PropertyGridDefinitionBindingBehavior PropertyItems="{Binding PosSettings}" DescriptionPath="Description" DisplayNamePath="ParameterName" GroupNamePath="ParameterTypeName" ValuePath="ConvertedParameterValue" />
         </i:Interaction.Behaviors>
      </telerik:RadPropertyGrid>

     

    and here is the PropertyGridDefinitionBindingBehavior  class:

    public class PropertyGridDefinitionBindingBehavior : Behavior<RadPropertyGrid>
    {
       protected override void OnAttached()
        {
            base.OnAttached();
            Initialize();
        }
     
        private void Initialize()
        {
     
            //this.DataContext = viewModel;
            //InitializeComponent();
            if (AssociatedObject == null)
            {
                return;
            }
     
            AssociatedObject.PropertyDefinitions.Clear();
            var propertyItemsList = PropertyItems as IEnumerable<object>;
            foreach (var setting in propertyItemsList)
            {
     
                var newDefinition = new PropertyDefinition(/*new ItemPropertyInfo(setting.ParameterName, Type.GetType(setting.DataTypeName), setting.Description)*/)
                {
                    Binding = new Binding { Source = setting, Mode = BindingMode.TwoWay, Path = new PropertyPath(ValuePath) },
                };
                 
                BindingOperations.SetBinding(newDefinition, PropertyDefinition.DescriptionProperty, new Binding { Source = setting, Mode = BindingMode.TwoWay, Path = new PropertyPath(DescriptionPath) });
                BindingOperations.SetBinding(newDefinition, PropertyDefinition.DisplayNameProperty, new Binding { Source = setting, Mode = BindingMode.TwoWay, Path = new PropertyPath(DisplayNamePath) });
                BindingOperations.SetBinding(newDefinition, PropertyDefinition.GroupNameProperty, new Binding { Source = setting, Mode = BindingMode.TwoWay, Path = new PropertyPath(GroupNamePath) });
     
                AssociatedObject.PropertyDefinitions.Add(newDefinition);
            }
            // Different values here _propertyGrid.PropertySetMode = PropertySetOperation.Union;
            AssociatedObject.Item = PropertyItems;
        }
     
        public object PropertyItems
        {
            get { return (object)GetValue(PropertyItemsProperty); }
            set { SetValue(PropertyItemsProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for PropertyItems.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PropertyItemsProperty =
            DependencyProperty.Register("PropertyItems", typeof(object), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(null, (s, a) =>
            {
                var me = s as PropertyGridDefinitionBindingBehavior;
                var oldValue = a.OldValue as ObservableCollection<object>;
                if (oldValue != null)
                {
                    oldValue.CollectionChanged -= me.ItemsCollectionChanged;
                }
     
                var newValue = a.NewValue as ObservableCollection<object>;
                if (newValue != null)
                {
                    newValue.CollectionChanged += me.ItemsCollectionChanged;
                }
                me.Initialize();
            }));
     
        private void ItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            Initialize();
        }
     
        public string ValuePath
        {
            get { return (string)GetValue(ValuePathProperty); }
            set { SetValue(ValuePathProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for ValuePath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValuePathProperty =
            DependencyProperty.Register("ValuePath", typeof(string), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(string.Empty));
     
        public string DescriptionPath
        {
            get { return (string)GetValue(DescriptionPathProperty); }
            set { SetValue(DescriptionPathProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for DescriptionPath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DescriptionPathProperty =
            DependencyProperty.Register("DescriptionPath", typeof(string), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(string.Empty));
     
        public string DisplayNamePath
        {
            get { return (string)GetValue(DisplayNamePathProperty); }
            set { SetValue(DisplayNamePathProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for DisplayNamePath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisplayNamePathProperty =
            DependencyProperty.Register("DisplayNamePath", typeof(string), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(string.Empty));
     
        public string GroupNamePath
        {
            get { return (string)GetValue(GroupNamePathProperty); }
            set { SetValue(GroupNamePathProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for GroupNamePath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty GroupNamePathProperty =
            DependencyProperty.Register("GroupNamePath", typeof(string), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(string.Empty));
     
        public Type DataTypePath
        {
            get { return (Type)GetValue(DataTypePathProperty); }
            set { SetValue(DataTypePathProperty, value); }
        }
     
        // Using a DependencyProperty as the backing store for DataTypePath.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataTypePathProperty =
            DependencyProperty.Register("DataTypePath", typeof(Type), typeof(PropertyGridDefinitionBindingBehavior), new PropertyMetadata(typeof(object)));
     
    }

    With the above code, I am able to set the property name, description, category and value for each specific record from the database.  I am doing it with a behavior rather than the xaml.cs code behind.

    This actually works, but each value has a different property type, stored in the table so I know its actual type name, but whatever I do each property is displayed and edited as a string. Is there any way to set the property type for each property, from each row in the database?

    Thank you again,
    Dave

  10. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 09 Dec 2013 Link to this post

    Hi,

    Generally, RadPropertyGrid will auto generate its PropertyDefinitions based on the type of the corresponding properties. It should be set this at property level.

    The way to control it from RadPropertyGrid would be to subscribe for the AutoGeneratingPropertyDefinition event and modify each of the generated definition. Please check our online documentation.

    Regards,
    Didie
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  11. David
    David avatar
    7 posts
    Member since:
    Nov 2013

    Posted 11 Dec 2013 Link to this post

    Thank you, but I believe that event is generated only if I auto-generate the property definitions.  I am building the property list using the Behavior shown in this thread.
  12. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 12 Dec 2013 Link to this post

    Hello Dave,

    You can try setting an EditorTemplate for the PropertyDefinitions you define. The code in this article shows it in Xaml, but you can also assign such in code.

    If it does not work for you, would it be possible for you to isolate the case in a demo solution which I can test locally?

    Regards,
    Didie
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  13. David
    David avatar
    7 posts
    Member since:
    Nov 2013

    Posted 13 Dec 2013 Link to this post

    Thank you Didi.  I think this is a good idea, as it looks like DataTemplate can provide the right editor generically.

    I have the data type name (eg, "System.String") in a property (called DataTypeName) of the item I am binding to, so I tried this code:
    PropertyDefinition newDefinition = new PropertyDefinition() { ... }
    newDefinition.EditorTemplate = new DataTemplate(setting.DataTypeName);
    The only effect of that was to make my values no longer show.  I wanted to try something simpler as a test, so I tried variations of this:
    newDefinition.EditorTemplate = new DataTemplate("System.String");
    ...thinking a text editor would appear if I were doing it right, but again all I get is no values, just the property list.  I also see no build or runtime errors.
    How would I actually create a DataTemplate for System types (ie, "System.String", "System.Boolean", "System.Int32", etc.)?
  14. Dimitrina
    Admin
    Dimitrina avatar
    3769 posts

    Posted 17 Dec 2013 Link to this post

    Hi,

    You have just created an empty DataTemplate. You will need to define a content to display within in it.
    You can check this forum thread on how to create a DataTemplate in code behind.

    Regards,
    Didie
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
Back to Top
UI for WPF is Visual Studio 2017 Ready