This is a migrated thread and some comments may be shown as answers.

PropertyGrid not displaying value on List of poco's

12 Answers 430 Views
PropertyGrid
This is a migrated thread and some comments may be shown as answers.
David
Top achievements
Rank 1
David asked on 27 Nov 2013, 06:32 PM

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?

12 Answers, 1 is accepted

Sort by
0
Dimitrina
Telerik team
answered on 28 Nov 2013, 10:11 AM
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 >>
0
David
Top achievements
Rank 1
answered on 04 Dec 2013, 12:04 AM
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
0
Dimitrina
Telerik team
answered on 04 Dec 2013, 08:27 AM
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 >>
0
David
Top achievements
Rank 1
answered on 04 Dec 2013, 05:40 PM
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
0
Dimitrina
Telerik team
answered on 05 Dec 2013, 11:35 AM
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 >>
0
David
Top achievements
Rank 1
answered on 05 Dec 2013, 10:16 PM

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

0
David
Top achievements
Rank 1
answered on 05 Dec 2013, 10:19 PM

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

0
Dimitrina
Telerik team
answered on 09 Dec 2013, 01:56 PM
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 >>
0
David
Top achievements
Rank 1
answered on 11 Dec 2013, 06:24 PM
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.
0
Dimitrina
Telerik team
answered on 12 Dec 2013, 07:44 AM
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 >>
0
David
Top achievements
Rank 1
answered on 13 Dec 2013, 10:10 PM
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.)?
0
Dimitrina
Telerik team
answered on 17 Dec 2013, 08:49 AM
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 >>
Tags
PropertyGrid
Asked by
David
Top achievements
Rank 1
Answers by
Dimitrina
Telerik team
David
Top achievements
Rank 1
Share this question
or