customFactory customization

Grids for WPF Forum

Posted 5 years ago by Sasha
Version: 14.2.0610
Avatar

Hi,

We have created propertyGrid with customFactory like in example.

I have two questions about customization property grid.

1. In example are used only string types. Is it possible to use another type and if yes, can you please point, what I am doing here wrong. Here I define my customFactory:

 protected override IList<IPropertyDataAccessor> GetProperties(object value, DataFactoryOptions options)
 {
     IList<IPropertyDataAccessor> dataAccessors;

     var uc = value as UserControlViewModel;
     if (uc != null)
     {
         // Create a list of property data accessor results
         dataAccessors = new List<IPropertyDataAccessor>();

         dataAccessors.Add(new CustomPropertyDataAccessor<UserControlViewModel, string>(uc, o => o.ControlName, "Control Name", null, "CategoryName", "Description"));
         dataAccessors.Add(new CustomPropertyDataAccessor<UserControlViewModel, int>(uc, o => o.ZIndex, "Z index", null, "CategoryName","CategoryName",));
     }
     else
     {
         // Fall back to using the base method's results for nested objects
         dataAccessors = base.GetProperties(value, options);
     }
 return dataAccessors;
}
    

 Here the problem is that when I try to modify ZIndex value in propertyGrid, I get InvalidCastException in setter in CustomPropertyDataAccessor:

 protected override object ValueInternal
 {
     get
     {
         return propGetter(target);
     }
     set
     {
         propSetter(target, (TValue)value);
     }
 }

 And it works perfectly with string variables like ControlName.

My ZIndex is :

 public override int ZIndex
 {
     get { return _zIndex; }
     set
     {
         _zIndex = value;
         RaisePropertyChanged();
     }
 }

 

 

2. We would like to set from code readOnly states like in example Selective ReadOnly. It's not very clear to me, where should I ovveride IPropertyDataAccessor CreatePropertyDataAccessor. My customFactory looks like:

 public class CustomFactory : CustomBaseFactory
    {
        protected override IList<IPropertyDataAccessor> GetProperties(object value, DataFactoryOptions options)
        {
        }
    }

 And CustomBaseFactory overrides IPropertyDataAccessor. But in debug I saw that code never comes to overriden IPropertyDataAccessor method. Where can I be wrong here?

Thank you.

Comments (5)

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

Hi Sasha,

1) What's happening here is that I think it's using BuiltinEditors.DynamicValueTemplateKey by default which binds the TextBox in the related property editor directly to Value, which is an integer.  So there is a cast exception.  If you tell the CustomPropertyDataAccessor to use BuiltinEditors.DynamicStringValueTemplateKey instead, it will work since that will bind its TextBox to ValueAsString instead, so two-way string conversion occurs.  We are updating our sample for the upcoming maintenance release to demo this.

2) I'm not sure which data factory base class you are using (we don't have a CustomBaseFactory class) but you would basically update the CustomPropertyDataAccessor class used in our Custom Factory sample to support IsReadOnly in some fashion.  One way would be to do what the Selective Read-only sample does with its data accessor implementation, or you could do something simpler.


Actipro Software Support

Posted 5 years ago by Sasha
Avatar

Thank you for your answer.

Posted 5 years ago by Sasha
Avatar

Sorry for the late response. The first issue is resolved. But I still can't figure out second one. So let me explain one more time.

I had a look at example Selective visibility and implemented like in example CustomPropertyDescriptorDataAccessor, IPropertyVisibility.

My CustomDataFactory has two overrides:

protected override IList<IPropertyDataAccessor> GetProperties(object value, DataFactoryOptions options)
{
    IList<IPropertyDataAccessor> dataAccessors;

    var uc = value as UserControl01ViewModel;
    if (uc != null)
    {
        // Create a list of property data accessor results
        dataAccessors = new List<IPropertyDataAccessor>();
              
        dataAccessors.Add(new CustomPropertyDataAccessor<ViewModel, double>(uc, o => o.Value,"PropertyName", Custom1TemplateKey, "Category", "Description"));
        dataAccessors.Add(new CustomPropertyDataAccessor<ViewModel, DateTime>(uc,o => o.LastDateTime, "PropertyName", Custom2TemplateKey,"Category", "Description"));
        
	 //If this property is true, make last one visible
	dataAccessors.Add(new CustomPropertyDataAccessor<ViewModel, bool>(uc, o => o.Offline,"MessungOffline", BuiltinEditors.CheckBoxValueTemplateKey, "Category", "Description"));
        dataAccessors.Add(new CustomPropertyDataAccessor<ViewModel, int>(uc, o => o.OfflineId,"OfflineKennung", BuiltinEditors.DynamicStringValueTemplateKey, "Category", "Description"));
    }
    else
    {
        // Fall back to using the base method's results for nested objects
        dataAccessors = base.GetProperties(value, options);
    }

    return dataAccessors;
}

protected override IPropertyDataAccessor CreatePropertyDataAccessor(IPropertyDataAccessor parent, object value, PropertyDescriptor propertyDescriptor)
{
    return new CustomPropertyDescriptorDataAccessor(parent, value, propertyDescriptor);
}

 And my Xaml style is:

 

 <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
        <Style TargetType="{x:Type propgrid:PropertyGridDataAccessorItem}">
            <Style.Triggers>
                <Trigger Property="DataAccessorType" Value="Category">
                    <Setter Property="IsExpanded">
                        <Setter.Value>
                            <MultiBinding>
                                <MultiBinding.Converter>
                                    <convertors:ExpandedCategoryConverter/>
                                </MultiBinding.Converter>
                                <Binding Path="DisplayName" RelativeSource="{RelativeSource Self}"/>
                                <Binding Path="ViewModel" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=UserControl}"/>
                            </MultiBinding>
                        </Setter.Value>
                    </Setter>
                </Trigger>
                <Trigger Property="DataAccessorType" Value="Property">
                    <Setter Property="Visibility" Value="{Binding RelativeSource={RelativeSource Self}, Path=DataContext.IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}" />
                </Trigger>
            </Style.Triggers>
        </Style>

 The problem is that while working with propertyGrid, overried CreatePropertyDataAccessor is never executed.

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

Hi Sasha,

The CreatePropertyDataAccessor method will get called by the base.GetProperties method if it locates properties that are mutable and not a collection.  In your case, perhaps you are catching all such properties in your 'if' statement.

What we had suggested in the last reply is accurate.  Use logic similar to what is in the "CustomPropertyDescriptorDataAccessor" class (from the SelectedReadOnly QuickStart) related to controlling its IsReadOnly property, but roll that logic into your "CustomPropertyDataAccessor" class instead.  Then you likely won't need a CreatePropertyDataAccessor override in your factory.


Actipro Software Support

Posted 5 years ago by Sasha
Avatar

Sorry, first time I misunderstood you. Today I tried and everything working.

Thank you.

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

Add Comment

Please log in to a validated account to post comments.