Question

Handling remove behavior in IList

Posted 2 months ago by Avatar Antoine Picard

Hi !

I need to handle the behavior of the add/remove button (+/-) from the IList editor. So I created an editor for IList with a label and a + button like this:

<grids:PropertyEditor PropertyType="collections:IList">
   <grids:PropertyEditor.ValueTemplate>
      <DataTemplate>
         <Grid>
            <Grid.ColumnDefinitions>
               <ColumnDefinition Width="*"/>
               <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Label Content="{Binding Value}" />
            <Button Grid.Column="1" Click="CollectionButton_OnClick" Content="+" BorderThickness="0"  Padding="5,0,5,0" Background="Transparent"/>
         </Grid>
      </DataTemplate>
   </grids:PropertyEditor.ValueTemplate>
</grids:PropertyEditor>

 So this is working as I want, I can control what's happening when I click on the + button.

Now I want to do the same thing for the - button, but as I don't know what will be the type inside my List (can be List<String> or anything else) I don't know how and where can I handle this ?


Comments (12)

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

Hi Antoine,

I'm not sure that is the best way to handle this.  Our default PropertyGrid value cell template has a ContentPresenter and two Buttons, one for add and one for remove.  The buttons are normally hidden unless the value is an editable list (add button shows) or an editable list item (remove button shows).  The buttons bind their Command to the AddChildCommand and RemoveCommand properties on the property model.  These two commands call related virtual AddChild and Remove methods when they are executed.  Thus what you really want to do is override the AddChild and Remove methods of the property model with your custom logic since that is where our default behavior is.

I think in other threads with you, we talked about how to get to those kinds of property models (CollectionPropertyDescriptorPropertyModel, etc.) via the factory.  If you have any questions, let us know.


Actipro Software Support
Posted 2 months ago by Antoine Picard

Hi !

As mentionned in this thread, I don't know why but I'm not able to have those buttons. I managed to get the minus button with a type converter but then my property isn't expandable anymore. Furthermore, my collection class (implementing IList) is in another project where, if possible, I wouldn't like to introduce any ActiPro element.

I tried to use the datafactory to create my editor and give it to any property of the right type but ValueTemplate is readOnly so I don't know if it's the right way.

So do you advice me to override Add/Remove Child methods in my dataFactory or in my code behind ?
Anyway, there must be a way to do what i asked previously.

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

Hi Antoine,

The AddChild and Remove methods are on the appropriate property models. To override them, you would need to create classes that inherit the property model classes whose methods would be called, and override the spots where the instances would normally be created to use your custom classes instead. That can be a little tricky due to the complexity of collection handling in PropertyGrid, but it would be the cleanest solution if you could get it working. I know you had trouble in other threads getting some functionality to work. If you could make a new simple sample project that showed the issues you are having and sent that to our support address referencing the related threads, we could try and help you sort those out. I believe you said you had trouble making a sample before.but if you are able to make one, please remove the bin/obj folders from the ZIP, and rename the .zip file extesion so it doesn't get spam blocked.

Back on your original question, that is the reason we have our add/remove buttons defined in the PropertyGrid.ValueContainerStyle's Template (defined via a Style Setter). The ControlTemplate for a TreeListViewItemCell there has a ContentPresenter (which will display any arbitrary property editor DataTemplate based on data type, etc.) and our add/remove buttons that show based on the CanAddChild and CanRemove property model values. 

If you do things where you are putting the remove button in the property editor DataTemplate instead, then you'd probably have to programmatically set your specific property editor when appropriate within the factory's CreatePropertyModel method.  You could probably call the base method to create a property model, look at the request.Parent to see if it's your collection, and if so, set the property model's ValuePropertyEditor property to select your property editor.


Actipro Software Support
Posted 2 months ago by Antoine Picard

Hi !

Okay so the first solution seems too tricky as you said, I have a really big and complex project so it'll be too hard to do this. For the same reason, it's hard for me to provide you a simple sample of my issue because my collection class is really big and implements (directly or not) around 20 other classes.

I'm really sorry but I don't understand your solution. I'm still learning and understanding WPF and your products so I didn't get what do I have to do and where.

I checked the request.Parent in the CreatePropertyModel method and it's mostly null but when I get on an item of my collection property I have my collection inside the parent so it seems good. I tried what you suggested but didn't saw any difference.

Thank you for your patience,

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

Hi Antoine,

Some of what we explain above might make more sense if you browse through the default XAML styles in Grids.  Or even browse the source code of the TypeDescriptorDataFactory class, etc.  I believe your company has a Blueprint license.

Beyond what's written above, it's going to be difficult to help without having a simple sample project we can both work from and discuss.  If you can trim way down your setup to just include in a sample the key concepts that cause it to happen, that would be best.


Actipro Software Support
Posted 2 months ago by Antoine Picard

Hi !

So first of all, I tried to create a simple sample project for you but I wasn't able to reproduce the issue. I added everything I needed, my collection class and everything else but the minus button is here.

I managed to make something working with a DataFactory. To make it short, I created a class inheriting from IPropertyModel and set IsImmutable and IsReadOnly to false and CanRemove to true. So now each time I get my collection class as a parent, I use this class instead of the basic one. It's working and I have the minus button ! But they are disabled and I don't know why.

Do you have any clue ? Maybe I should do the same trick for the CollectionPropertyDescriptorPropertyModel class and override one of its property ?

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

Hi Antoine,

The visibility of the remove button is based on CanRemove being true, while the button's Command gets set to RemoveCommand.  Our default implementation of RemoveCommand has its can-execute tied to CanRemove.  So really, the button should only be showing up if it's going to end up being enabled.  It's hard to say why that isn't happening without a sample to debug.  Perhaps your custom property model class isn't inheriting some of our base ones that wire that functionality (like the RemoveCommand) up?

The same kind of setup is true for the add button.


Actipro Software Support
Posted 2 months ago by Antoine Picard

Hi !

As I said before, my class is inheriting IPropertyModel, I forced the CanRemove & IsReadOnly properties to true and checked the RemoveCommand wich seems to work (I don't know what I should have inside this).

I also created a custom class inheriting CollectionPropertyDescriptorPropertyModel and tried to set the CanRemove property to true but no improvment. In this constructor, I set default values for isCollectionReadOnly and areItemsReadOnly as false.

The add button works perfectly now that I set CollectionPropertyDisplayMode="EditableInline" so no issue with it anymore.

I'm still working a bit with my sample project because this one is working and I don't know why.

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

Hello,

Our standard RemoveCommand is:

removeCommand = new DelegateCommand<object>(p => {
	this.Remove();
}, p => {
	return this.CanRemoveResolved;
});

CollectionPropertyDescriptorPropertyModel represents the collection property, so only handle the add-related functionality on that property model.  Adding remove functionality won't really do anything. 

The PropertyDescriptorPropertyModel created for list items (generally for ExpandableCollectionConverter.ListItemPropertyDescriptor instances) is where you want remove functionality added.  By default the property model CanRemove will return propertyDescriptor.CanRemove, which is this for ListitemPropertyDescriptor:

return (!isCollectionReadOnly) && (list != null) && (!list.IsReadOnly) && (!list.IsFixedSize);

Actipro Software Support
Posted 2 months ago by Antoine Picard

Hi !

As you suggested, I created a class inheriting PropertyDescriptorPropertyModel and in the CreatePropertyModel function, whenever I want I return this new class. This new class has its CanRemove forced at true so now, the minus button is visible and enabled but nothing happen when I click on it. I overrided the Remove function and when I click on the button, this function is correctly called with the base.Remove but no removal. I tried to implement my own remove function but it's not that easy with all the different types.

Any suggestion on this ?

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

Hello,

It's hard to say without debugging a sample.  But if it wasn't returning CanRemove = true earlier (you had to override that), then the criteria for removal isn't being passed and the same sort of criteria is probably being used in our Remove method logic.  Either your property descriptor doesn't pass the logic used for CanRemove (such as that described above) or maybe a default ExpandableCollectionConverter.ListItemPropertyDescriptor-like instance isn't even being created like in a scenario where your collection isn't a plain IList, etc.


Actipro Software Support
Posted 2 months ago by Antoine Picard

Hi,

So I found a patch up for my issue, I still don't know why it wasn't not working but as it's working now I won't take any more time to work on this.

My alternative is to create a class inheriting PropertyDescriptorPropertyModel, force CanRemove to true and override the Remove function like this 

public override 
{
 ((IList)_target).Remove(Value);
 RaiseChildPropertyRemovedEvent(new PropertyModelChildChangeEventArgs((IPropertyModel)Parent, Value));
} 

 My sample is still working without this patch so I can't send you anything reliable.

Thanks for your help,

Antoine

[Modified 2 months ago]

Information The latest build of this product (2018.1 build 0673) was released 1 month ago, which was after the last post in this thread.

Add a Comment

Please log in to a validated account to post comments.