PropertyGrid don't update with custom DataFactory

Grids for WPF Forum

Posted 2 years ago by BenjaminLopVic - France
Version: 22.1.3
Platform: .NET 6.0
Environment: Windows 11 (64-bit)
Avatar

Hello,

My simplfied model is a folder that contains files. I want to display a single folder in a propertyGrid and in that PropertyGrid I don't want a collection of files but a new line for each files.

The problem is that when there is new file I need to refresh manualy but if I remove my DataFactory it works, the propertyGrid refresh itself. 

I made a simple model with the same issue to help you to understand : 

Model : 

public class Folder
{
    public Folder(string name)
    {
        Name = name ?? throw new ArgumentNullException(nameof(name));
        Files = new ObservableCollection<File>();
    }

    public string Name { get; private set; }
    public ObservableCollection<File> Files{ get; private set; }
}

public class File
{
    public File(string name, string content)
    {
        Name = name ?? throw new ArgumentNullException(nameof(name));
        Content = content ?? throw new ArgumentNullException(nameof(content));
    }

    public string Name { get; private set; }
    public string Content { get; set; }
}

PropertyModel :

internal class FilePropertyModel : CachedPropertyModelBase
{
    private File file;

    public FilePropertyModel(File file)
    {
        this.file = file ?? throw new ArgumentNullException(nameof(file));
    }

    protected override bool CanResetValueCore => true;

    protected override bool IsMergeableCore => true;

    protected override bool IsModifiedCore => true;

    protected override bool IsValueReadOnlyCore => true;

    protected override string NameCore => file.Name;

    protected override object TargetCore => file;

    protected override object ValueCore { get => file.Content; set => file.Content = value.ToString(); }

    protected override Type ValueTypeCore => typeof(string);
}

And DataFactory :

public class FolderDataFactory : TypeDescriptorFactory
{
    public FolderDataFactory()
    {
    }

    protected override IList<IPropertyModel> GetPropertyModels(object dataObject, IDataFactoryRequest request)
    {
        if(dataObject is Folder folder)
        {
            var propertyModels = new List<IPropertyModel>();
            var propertyDescriptors = TypeDescriptor.GetProperties(folder);

            propertyModels.Add(new PropertyDescriptorPropertyModel(folder, propertyDescriptors[nameof(folder.Name)]));
            foreach (var file in folder.Files)
            {
                propertyModels.Add(new FilePropertyModel(file));
            }
            return propertyModels;
        }
        return base.GetPropertyModels(dataObject, request);
    }
}

Thanks.

Comments (6)

Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hello,

TreeListBox (a base class of the PropertyGrid control) supports watching the node children collections for INotifyCollectionChanged implementations, which is probably why it works for you when not using a data factory, as your Folders.Files collection is observable.

However data factories for PropertyGrid are combining things like categories and properties together.  They do this in a List<IDataModel> by default, returned in the dataFactory.GetDataModels method.  It's not really made for dynamic changes there.  That being said, you might be able to override the GetDataModels method instead of GetPropertyModels and return an ObservableCollection of PropertyModels there.  Then if you alter that existing collection later, the PropertyGrid should be able to get the changes without needing a manual refresh.


Actipro Software Support

Posted 2 years ago by BenjaminLopVic - France
Avatar

Hello,

I have overriden the GetDataModels with a custom DataModel but it disn't seem to work. I didn't found any documention or sample to implemnt IDataModel or DataModelBase.

This is how I implemented it : 

internal class CustomDataModel : DataModelBase
{
    public CustomDataModel(Folder folder)
    {
        foreach (var file in folder.Files)
        {
            Children.Add(new FilePropertyModel(file));
        }
    }
}

And now my DataFactory don't override GetPropertyModels but GetDataModels like this :

public override IList<IDataModel> GetDataModels(IDataFactoryRequest request)
{
    ObservableCollection<IDataModel> dataModels = new ObservableCollection<IDataModel>();
    foreach (var obj in request.DataObjects)
    {
        if (obj is Folder folder)
            dataModels.Add(new CustomDataModel(folder));
    }
    return dataModels;
}

[Modified 2 years ago]

Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hello,

IDataModel is the base interface for IPropertyModel and ICategoryModel, which are all property grid model concepts.  If you want PropertyGrid to be showing these folders like properties, then you need to be returning IPropertyModel objects, such as the ones you originally posted. 

Our default GetDataModels implementation ends up calling into GetPropertyModels, along with handling categorizing, etc.  Since you override GetDataModels now, you can just return them right there in GetDataModels instead.

I hope that helps explain it a little more.  And if you still have trouble, please tell us exactly what didn't work.


Actipro Software Support

Posted 2 years ago by BenjaminLopVic - France
Avatar

Hello,

Ok, I override GetDataModels like this now :

public override IList<IDataModel> GetDataModels(IDataFactoryRequest request)
{
    ObservableCollection<IDataModel> dataModels = new ObservableCollection<IDataModel>();
    foreach (var obj in request.DataObjects)
    {
        if (obj is Folder folder)
        {
            foreach (var file in folder.Files)
            {
                dataModels.Add(new FilePropertyModel(file));
            }
        }
    }
    return dataModels;
}

But I still have the same problem, when I add files to the folder I have to refresh the PropertyGrid to see them.

Posted 2 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hello,

This is a complex scenario so it's hard to say what's happening without debugging a simple sample project showing the issue.  If you'd like to put together a new simple sample project that shows this, please send it to our support address and mention this thread.  Be sure to exclude the bin/obj folders so they don't get spam blocked.

While we're talking though, may I ask why you are trying to use PropertyGrid to display this folder/file information?  It seems like using either the base TreeListBox or TreeListView would generally be a better option for this kind of scenario.  PropertyGrid has additional layering on top of those base controls that probably adds more complexity than you need, and we know that using the base controls makes it easy to see any updates to your model.

Our Shell controls are also available, which are made to show folder/file structures.  The controls in that product are based on TreeListBox and TreeListView too.  Are those an option for you?


Actipro Software Support

Posted 2 years ago by BenjaminLopVic - France
Avatar

Hello,

Ok, thanks, I will do that :)

I agree this is a strange way to display that type of informations in a PropertyGrid but this is juste a sample project. My real project is more complex and is not about files and folders. I thought a simple use case like this is easier to understand and don't need any context.

The latest build of this product (v24.1.1) was released 2 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.