Not understanding how to set the style for .NET 5 C1PropertyGrid.CategoryStyle

Posted by: Jeff.Huckins on 1 March 2022, 10:27 am EST

  • Posted 1 March 2022, 10:27 am EST

    I am using a .NET 5 C1PropertyGrid in my application, which has significant custom styles. I have set what properties I can in a C1PropertyGrid style in my resource dictionary as follows:
        <!--The C1PropertyGrid-->
    <Style TargetType="c1:C1PropertyGrid">
    <Setter Property="SnapsToDevicePixels" Value="True"/>
    <Setter Property="Background" Value="{StaticResource DarkerBaseBrush}"/>
    <Setter Property="BorderBrush" Value="{StaticResource blue-3Brush}"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Foreground" Value="{StaticResource defaultTextBrush}"/>
    <Setter Property="PropertyBorderBrush" Value="{StaticResource blue-3Brush}"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    </Style>


    But I don't know how to set the CategoryContainerStyle or the CategoryStyle because I have no idea what the TargetType is for them.

    I've attached an image of what it looks like in my application currently.
  • Replied 1 March 2022, 3:25 pm EST

    Hello Jeff,

    Thanks for providing the Snapshot and code snippet.

    In order to achieve your requirement, you can set target-type as ExpanderButton and C1Expander to the CategoryStyle and CategoryContainerStyle respectively. (see code snippet)


    <c1:C1PropertyGrid.CategoryStyle>
    <Style TargetType="c1:ExpanderButton">
    <Setter Property="Background" Value="Red"/>
    </Style>
    </c1:C1PropertyGrid.CategoryStyle>
    <c1:C1PropertyGrid.CategoryContainerStyle>
    <Style TargetType="c1:C1Expander">
    <Setter Property="Background" Value="Black"/>
    </Style>
    </c1:C1PropertyGrid.CategoryContainerStyle>


    Please refer the attached sample for the same : PropertyGridContainerStyleDemo.zip

    Best Regards,
    Nitin
  • Replied 2 March 2022, 2:12 pm EST

    That appears to work, but now I need to change the style of the text boxes with the white background to match our styles
  • Replied 2 March 2022, 8:17 pm EST

    Hi Jeff,

    Thanks for the acknowledgement.

    JFYI, PropertyBox editor is not specefic and it may be a custom editor, you can't directly set editor's style.
    In order to achieve your requirement, you need to handle PropertyBoxAdded event for C1PropertyGrid as : (see code snippet)


    private void PropertyBox_Added(object sender, C1.WPF.PropertyGrid.PropertyBoxChangedEventArgs e)
    {
    if(e.PropertyBox.CurrentEditor is TextBox)
    {
    var txtBox = (e.PropertyBox.CurrentEditor as TextBox);
    txtBox.Background = Brushes.LightGray;
    txtBox.Foreground = Brushes.Red;
    }
    }


    Please refer the attached modified sample for the same : PropertyGridContainerStyleDemo_Mod.zip

    Best Regards,
    Nitin
  • Replied 3 March 2022, 7:12 am EST

    Thank you very much!
  • Replied 9 March 2022, 5:34 am EST

    That works, but I need to change the read-only background to be the same as the background for editable TextBox.

    I also have one StringEditor that still has the White background.

    Lastly, all of the property editors are read-only, which shouldn't be, since the properties in the class object have read-only set to false like so:

    [Code] /// <summary>
    /// Location of this action (User directory, group directory, or system directory)
    /// </summary>
    [CategoryAttribute("Info"),
    DescriptionAttribute("Location of this sequence(User directory, group directory, or system directory)"),
    ReadOnlyAttribute(false)]
    public override ActionLocation SaveLocation
    {
    get { return m_Location; }
    set
    {
    if (m_Location != value)
    {
    m_Location = value;
    OnPropertyChanged();
    }
    }
    }
    [/Code]
  • Replied 3 March 2022, 11:48 pm EST

    Hi Jeff,

    Thanks again for reaching out to us with your query.

    Editor will be disabled if bounded property is read-only.
    JFYI, If any of the editor is disabled, then the DisabledVisualElement C1Border will visible over the editor with less opacity background.
    You need to hide this C1Border or make it as Transparent. (see code snippet)


    private void PropertyBox_Added(object sender, C1.WPF.PropertyGrid.PropertyBoxChangedEventArgs e)
    {
    if(e.PropertyBox.CurrentEditor is TextBox)
    {
    var txtBox = (e.PropertyBox.CurrentEditor as TextBox);
    txtBox.Background = Brushes.Black;
    txtBox.Foreground = Brushes.White;

    //Make DisabledVisualElement transparent
    var bdr = txtBox.Template.FindName("DisabledVisualElement",txtBox) as C1Border;
    bdr.Visibility = Visibility.Collapsed;
    }
    }


    Please refer the attached sample for the same:PropertyGridReadOnlyEditor.zip

    Best Regards,
    Nitin
  • Replied 6 March 2022, 3:43 pm EST

    OK, I have figured out a few things:

    1. The C1PropertyGrid does not handle virtual properties, which is why I've been confused about why editors are disabled. This works fine in WinForms standard PropertyGrid (not a C1 control).

    2. Now that I've changed the background for the EnumEditor, the dropdown is still using the white background, so this needs to be resolved. Image below...

    3. There is still a string editor that has a white background, so this is a problem.

    4. What I really need to do is set the string editor (TextBox) Style to the application TextBox style so that the correct visual state indicators are there, but that doesn't work because an exception is thrown when I do that due to something to do with a C1Style.

  • Replied 4 March 2022, 9:21 am EST

    Sorry for all of the posts, but I keep trying different things. I need to implement a custom editor for a list of objects that can be edited. I've been searching for examples, but can't find any. The ComponentOne Sample Explorer doesn't have a useful sample for C1PropertyGrid, so could you please provide one?
  • Replied 6 March 2022, 11:44 pm EST

    Hello Jeff,

    1. Editor will be disabled if the property is read-only. There's no issue with the virtual properties, it can be visible as usual. Could you please clarify your requirement for the virtual properties. It seems okay at our end.

    2. The default background of dropdown(popup) of EnumEditor already set. You need to find the ListView from EnumEditor's template, then you can set background on it.(see code snippet)

    if (e.PropertyBox.CurrentEditor is EnumEditor)
    {
    var enumEditor = (e.PropertyBox.CurrentEditor as EnumEditor);
    enumEditor.Background = Brushes.PeachPuff;
    var listView = enumEditor.Template.FindName("ListView", enumEditor) as C1ListView;
    listView.Background = Brushes.PeachPuff;
    }

    Please refer the modified sample for the same: PropertyGridReadOnlyEditor_Mod.zip

    3. and 4. Could you please provide a small sample so that we can replicate this behavior and assist you accordingly. This is difficult to understand that how you are using StringEditor.

    For the CustomEditor, you need to implement ITypeEditorControl interface to the custom editor class and can give your own implementation to achieve your requirement. You can refer here for the same: https://www.grapecity.com/componentone/docs/wpf/online-extended/CreatingCustomEditors.html

    Please refer the CustomEditor(editable list) sample for the same: PropertyGrid_ListCustomEditor.zip

    Best Regards,
    Nitin
  • Replied 7 March 2022, 4:38 pm EST

    Hi, Nitin, regarding the virtual properties, the base class has virtual properties ReadOnlyAtrribute set to true, while most of the subclasses the ReadOnlyAttribute set to false. This is the problem.

    Regarding my item 3, you can see clearly in one of the images in my last post that one of the string editors has a white background, while the others don't. I set a breakpoint in the PropertyBoxAdded handler to see what editor types are added and they are all string editors with the exception of the one EnumEditor.

    Thanks for the assistance on the other items. I truly appreciate your help, however, I'm using .NET 5 and the .NET 5 C1 controls and cannot find the C1ListView. It does not get resolved in the C1.WPF namespace and there is no C1.WPF.ListView namespace as there is for .NET 6. As a matter of fact, when I set a break point after the line to get the ListView template, the template isn't found. The call to enumEditor.Template.FindName("ListView", enumEditor) returns null.

    I managed to figure out how to create a custom property editor that I need, as none of the available examples were helpful. But, thank you for the effort. However, I do need to know how to cause the ValueChanged event to fire using the member, public event PropertyChangedEventHandler ValueChanged;
  • Replied 7 March 2022, 4:10 pm EST

    Nitin,
    Here is the property declaration for the string property that is showing up with a white background. The PropertyGrid is also making it read-only even though the ReadOnlyAttribute for the derived class is set to false:

    For the base class:

    /// <summary>
    /// Version String
    /// </summary>
    [CategoryAttribute("Info"),
    DescriptionAttribute("Version string"),
    ReadOnlyAttribute(true)]
    public virtual string Version
    {
    get { return this.m_sVersion; }
    set
    {
    if (m_sVersion != value)
    {
    m_sVersion = value;
    OnPropertyChanged();
    }
    }
    }


    For the derived class:


    [CategoryAttribute("Info"),
    DescriptionAttribute("Version string"),
    ReadOnlyAttribute(false)]
    public override string Version
    {
    get { return this.m_sVersion; }
    set
    {
    if (m_sVersion != value)
    {
    m_sVersion = value;
    OnPropertyChanged();
    }
    }
    }
  • Replied 7 March 2022, 8:10 pm EST

    Hi Jeff,

    1. Virtual read-only property overriding into subclass with read-only attribute sets to false will not disable in the PropertyGrid. As if PropertyBox is referring to the sub-class property.
    This is not disabled at our end. We have attached a sample for you, you can also update this sample accordingly to replicate the behavior.

    Refer modified sample : PropertyGridReadOnlyEditor_Mod2.zip

    2. This is extremely difficult to replicate this behavior as we are unaware about your implementation. Please provide a small sample, that would be helpful to replicate at our end.

    3. C1ListView available in .Net5 version(refer image)


    Be sure, while finding "ListView" template from EnumEditor, the PropertryBox is loaded in the view. If you're finding "ListView" template from EnumEditor in PropertyBoxAdded event handler, then it shouldn't returns null. (see image)





    4. We are happy that you've created a custom control on your own. The basic thing is you need to inherit a control for the behaviors and implement the ITypeEditorControl interface. Then you can customize the editor accordingly.
    The ValueChanged event fires when the value of the property changes. We have attached a modified sample you can refer for the same: PropertyGrid_ListCustomEditor_Mod.zip

    Best Regards,
    Nitin
  • Replied 8 March 2022, 6:42 am EST

    Thanks, Nitin,
    I discovered that C1ListView was added to the WPF edition after version 100, which is what version I was using in our application. I updated to a later version and now find the C1ListView. Now that I have, I have new issues with the dropdown for the EnumEditor.

    I want to get rid of the corner radius for the dropdown. I tried to set the C1ListView.CornerRadius to a value of zero, but that didn't work.

    Also, after setting the background and foreground for the C1ListView, there is a white band along the top and bottom of the dropdown, which I need to remove. Image added here. Here is the code I'm using to set the colors, etc. for the C1ListView:


    if (e.PropertyBox.CurrentEditor is EnumEditor enumEditor)
    {
    enumEditor.Foreground = FindResource("TextBrush") as Brush;
    enumEditor.Background = FindResource("DarkerBaseBrush") as Brush;
    enumEditor.BorderBrush = FindResource("BaseBorderBrush") as Brush;
    var listView = enumEditor.Template.FindName("ListView", enumEditor) as C1ListView;
    listView.Background = FindResource("DarkerBaseBrush") as Brush;
    listView.Foreground = FindResource("TextBrush") as Brush;
    listView.CornerRadius = new CornerRadius(0);
    }
  • Replied 8 March 2022, 6:39 pm EST

    Hi Jeff,

    Thanks for the snapshot.

    Oh, we thought you're using latest version. We are happy that you've got the C1ListView.

    In order to style full dropdown popup instead ListView, you need to find DropDown element from its template and then you can set PopupStyle as: (see code snippet)

    <Window.Resources>
    <Style x:Key="popupStyle" TargetType="c1:C1Border">
    <Setter Property="Background" Value="PeachPuff"/>
    <Setter Property="Foreground" Value="Red"/>
    <Setter Property="BorderBrush" Value="Black"/>
    <Setter Property="BorderThickness" Value="1"/>
    </Style>
    </Window.Resources>
    ......................................................................................................................................
    private void PropertyBox_Added(object sender, C1.WPF.PropertyGrid.PropertyBoxChangedEventArgs e)
    {
    //For separator color
    var separator =e.PropertyBox.Template.FindName("6_T", e.PropertyBox) as C1Border;
    separator.Background = Brushes.Red;

    //For enum editor and popup styling
    if (e.PropertyBox.CurrentEditor is EnumEditor)
    {
    var enumEditor = (e.PropertyBox.CurrentEditor as EnumEditor);
    enumEditor.Background = Brushes.PeachPuff;
    var dropdown = enumEditor.Template.FindName("DropDown", enumEditor) as C1DropDown;
    dropdown.PopupStyle = FindResource("popupStyle") as Style;
    }
    }


    Please refer the attached sample for the same: EnumEditorStyling.zip

    Best Regards,
    Nitin
  • Replied 9 March 2022, 5:31 am EST

    Nitin, thank you very much for that advice. It works great.

    However, I am experiencing an issue with the custom Property Editors. When a new C1PropertyGrid.SelectedObject is set, I get the following exception:

    System.ArgumentException: 'Must disconnect specified child from current parent Visual before attaching to new parent Visual.'

    I'm assuming that it has something to do with the Detach() method of the custom editor, which currently does nothing. I know it is related to the custom property editors because, if I remove them from the C1PropertyGrid.AvailableEditors list, I don't get the exception.

    Here is the code for one of my custom editors:


    using C1.WPF.PropertyGrid;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;

    namespace Views.PropertyGridEditors
    {
    /// <summary>
    /// C1PropertyGrid List Property Editor
    /// </summary>
    public class SequenceCategoryEditor : Grid, ITypeEditorControl
    {
    public event PropertyChangedEventHandler ValueChanged;

    /// <summary>
    /// The Sequence categories collection
    /// </summary>
    private CmiAction Action { get; set; }

    public void Attach(PropertyAttribute property)
    {
    if (Supports(property))
    {
    Action = property.SelectedObject as CmiAction;

    // Add the controls to this StackPanel
    CreateControls(Action.Categories.GetList(), out TextBox textBox, out Button button);
    }
    }

    /// <summary>
    /// Add the controls that will show in the C1PropertyGrid PropertyBox
    /// </summary>
    /// <param name="categories"></param>
    private void CreateControls(ObservableCollection<string> categories, out TextBox text, out Button button)
    {
    // Create the columns
    ColumnDefinition textColumn = new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) };
    ColumnDefinition buttonColumn = new ColumnDefinition() { Width = GridLength.Auto };
    ColumnDefinitions.Add(textColumn);
    ColumnDefinitions.Add(buttonColumn);

    // Add the TextBox
    text = new TextBox() { Margin = new Thickness(0, 0, 3, 0), Style = FindResource(typeof(TextBox)) as Style, HorizontalAlignment = HorizontalAlignment.Stretch };
    text.TextChanged += Text_TextChanged;
    Children.Add(text);
    UpdateEditorText(categories);

    // Add the Button
    button = new Button() { Margin = new Thickness(0), Style = FindResource(typeof(Button)) as Style };
    button.Content = "...";
    button.Width = 30;
    button.FontSize = 14;
    button.FontWeight = FontWeights.Bold;
    button.Click += Button_Click;
    Children.Add(button);

    // Set column for the controls
    text.SetValue(Grid.ColumnProperty, 0);
    button.SetValue(Grid.ColumnProperty, 1);
    }

    /// <summary>
    /// Show the SequenceCategoriesEditWindow
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Button_Click(object sender, RoutedEventArgs e)
    {
    SequenceCategoriesEditWindow editor = new SequenceCategoriesEditWindow(Action.Categories.GetList());

    // If user presses OK button, update the Action categories
    if (editor.ShowDialog() == true)
    {
    Action.Categories.SetList(editor.SequenceCategoriesView.TextItems);
    UpdateEditorText(Action.Categories.GetList());
    }
    }

    /// <summary>
    /// Update the comma separated list of strings in the TextBox child
    /// </summary>
    /// <param name="categories"></param>
    private void UpdateEditorText(ObservableCollection<string> categories)
    {
    StringBuilder sb = new StringBuilder();
    if (categories.Count > 0)
    {
    sb.Append(categories[0]);
    }

    for (int i = 1; i < categories.Count; i++)
    {
    sb.AppendFormat(", {0}", categories[i]);
    }

    (Children[0] as TextBox).Text = sb.ToString();
    (Children[0] as TextBox).ToolTip = sb.ToString();
    }

    /// <summary>
    /// Don't allow changes in the textBox
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Text_TextChanged(object sender, TextChangedEventArgs e)
    {
    e.Handled = true;
    }

    public ITypeEditorControl Create()
    {
    return this;
    }

    public void Detach(PropertyAttribute property)
    {
    // Do nothing?
    }

    public bool Supports(PropertyAttribute Property)
    {
    return Property.PropertyInfo.PropertyType == typeof(CmiSequenceCategoryList);
    }
    }
    }


    Is there not somebody at GrapeCity that lives in the US so that I don't have to wait a day for responses? Just wondering. As you can imagine, it results in huge delays for the software release.
  • Replied 9 March 2022, 6:01 am EST

    Nitin, I actually modified your sample for custom editor by adding multiple Person objects to a listbox and setting the C1PropertyGrid.SelectedObject to the selected Person in the ListBox. When changing the C1PropertyGrid.SelectedObject, the same exception is thrown. It is related to your custom editor, so I need you to resolve your error and let me know how to fix mine.

    I've attached the updated example

    thanks!C1PropertyGrid Custom Editor.zip
  • Replied 9 March 2022, 7:24 am EST

    Sorry, a couple more things:
    1. I changed the background for the BoolEditor to a dark blue color. Now the check mark, being black, doesn't show up against the dark blue background, so I need to set the stroke color for the check mark to white to match our CheckBox style.
  • Replied 9 March 2022, 9:49 pm EST

    Hello Jeff,

    Thanks for the updated sample.

    1. Just a little change. You need to return new instance of custom editor from Create Method. So, it will attach new object and there'll be no error while removing current object.
    Please refer the attached modified sample for the same : C1PropertyGrid Custom Editor_Mod.zip

    2. You can change stroke color for the BoolEditor's checkbox mark by handling PropertyBoxAdded event as : (see code snippet)

    private void PropertyBox_Added(object sender, C1.WPF.PropertyGrid.PropertyBoxChangedEventArgs e)
    {
    if (e.PropertyBox.CurrentEditor is BoolEditor)
    {
    var booleditor = (e.PropertyBox.CurrentEditor as BoolEditor);
    var chkBorder = booleditor.Template.FindName("checkBoxBorder", booleditor) as Border;
    var optionMark = booleditor.Template.FindName("optionMark", booleditor) as Path;
    chkBorder.Background = Brushes.DarkBlue;
    optionMark.Fill = optionMark.Stroke = Brushes.White;

    }
    }


    Please refer the attache sample for the same: BoolEditorStyling.zip

    Best Regards,
    Nitin
  • Replied 10 March 2022, 1:25 pm EST

    OK, I'm almost there.

    Current issue: There are SOME properties in the class hierarchy for which the C1PropertyGrid.PropertyBoxAdded event does not get fired.

    This results in some built-in editors that do not get the color scheme updated in the event handler. I've included one image showing one of the classes in the hierarchy for which the event is fired for ALL browsable properties and another image showing the same properties for a different class in the hierarchy for which the event is not fired for the SAME virtual properties.

    The images are of the windows in the sample project from you that I modified to include all of our styles, colors and custom editors. I will upload the sample to the next comment.

    If I can get this last thing resolved, I have only one other need: Change the color or the white vertical bars to the right of each of the property names.
  • Replied 10 March 2022, 1:27 pm EST

    Here is the sample project with all of our styles, colors and custom editors and a couple of the actual classes from our class hierarchy so you have an exact replication.

    C1PropertyGrid Our Styles PropertyBoxAdded NOT Called.zip
  • Replied 11 March 2022, 12:22 am EST

    Hi Jeff,

    Thanks for the updated sample.

    1. We have replicated this issue at our end. So, we have escalated it to the development team. We will get back to you once we have any update from them.[Internal Tracking Id - C1XAML-29145]

    2. You can change the PropertyBox vertical separator color by handling PropertyBoxAdded event as:(see code snippet)

    private void PropertyBox_Added(object sender, C1.WPF.PropertyGrid.PropertyBoxChangedEventArgs e)
    {
    var separator = e.PropertyBox.Template.FindName("6_T", e.PropertyBox) as C1Border;
    separator.Background = Brushes.Red;
    }


    Please refer the attached sample for the same : PropertyGridSeparatorColor.zip

    Regards,
    Nitin
  • Replied 29 March 2022, 1:18 pm EST

    Nitin, the bug you referenced as "Internal Tracking Id - C1XAML-29145" I need you to add a support ticket for me for that. We're waiting for this fix to be able to release our software product on schedule.
  • Replied 29 March 2022, 8:47 pm EST

    Hi Jeff,

    This issue(C1XAML-29145) is fixed and will available in 2022v1 hotfix. You need to wait till public release.
    Hope you will understand.

    Best Regards,
    Nitin
  • Replied 31 March 2022, 9:51 am EST

    Hi, Nitin. Yes, I understand. But I need a hotfix for the version that I am using, not the latest. Can you confirm that there will be a hotfix that I can apply to version 5.0.20213.155?

    Thanks!
  • Replied 31 March 2022, 5:40 pm EST

    Hi Jeff,

    Is there have any specific reason that you are asking for hotfix version for 5.0.20213.155.
    Can't you upgrade to the latest version?
    Then we will try to arrange the private hotfix for you if possible.

    Waiting for your response.

    Regards,
    Nitin

  • Replied 7 April 2022, 2:07 am EST

    What version has the fix in it?
  • Replied 7 April 2022, 10:02 pm EST

    Hi Jeff,

    We have mentioned earlier that this is fixed in 2022v1 Hotfix(which is not public yet) where 2022V1 release is public. You can wait till 2022v1 Hotfix will release. ETA for this release is at the end of April.

    Best Regards,
    Nitin.
  • Replied 10 April 2022, 4:39 am EST

    Nitin,
    How will I know when the hotfix is released?
  • Replied 10 April 2022, 8:33 pm EST

    Hi Jeff,

    Don't worry, we will inform you whenever the 2022V1 Hotfix will release publicly.
    You can also check and download the public release builds and hotfix build on ComponentOneControlPanel.(see gif)



    JFYI, You can also check and download public builds including hotfix from Nuget.

    Best Regards,
    Nitin.
  • Replied 11 April 2022, 10:34 am EST

    Nitin,
    This is great. I use Nuget for my C1 components, so that will be great.
  • Replied 9 May 2022, 10:36 am EST

    The hotfix release is still not available
  • Replied 9 May 2022, 9:00 pm EST

    Hi Jeff,

    Apologize for the delay.

    2022v1 hotfix is released publicly. You can download it from nuget as well as from ComponentOneControlPanel. Control version is 6.0.20221.222. You can check https://www.nuget.org/packages/C1.WPF.PropertyGrid/.

    Please refer the image for the ComponentOneControlPanel:


    This issue is fixed in this version. Please check at your end too.

    Best Regards,
    Nitin.
Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels