C1ThemeController.ApplyTheme: prevent theming of subcontrols

Posted by: wknauf on 28 May 2019, 3:09 am EST

    • Post Options:
    • Link

    Posted 28 May 2019, 3:09 am EST

    Hi C1,

    we call C1ThemeController.ApplyTheme to apply a theme to a form. The parameter “applyThemeToSubTree” allows us to prevent theming of a subcontrol.

    A sample might be a panel which has a certain back color - this can be e.g. an explanation of colors used in a C1FlexGrid. The back color of this panel must not be changed to the theme color.

    But we also have rather complex forms, where a form contains (dynamically created) subsubsub UserControl instances, and only those nested subcontrols know about non-themeable controls. So I don’t want to add code to the root form which has to check for non-themeable controls on sub controls.

    My suggestion is that you add an interface “ICanApplyTheme” with a method “bool CanApplyTheme(Control subcontrol)”: if this interface is defined on a user control, C1ThemeController calls this method for all child controls of the UserControl. So the UserControl can prevent theming of specific sub controls.

    As multiple (and nested) controls in the control tree of a form can implement this interface, it would have to stack: if a control implements “ICanApplyTheme”, and another subcontrol of this control also implements the interface, for all subcontrols of the inner “ICanApplyTheme” control the “CanApplyTheme” of this inner “ICanApplyTheme” implementation the “CanApplyTheme” method shall be called, but not the method of the outer parent control.

    Hope I could make my requirement clear ;-).I could create a sample to show my requirement, but without implementation of the ThemeController logic, it would not make much sense.

    What do you think about this idea?

    Best regards

    Wolfgang

  • Posted 3 June 2019, 4:28 am EST

    Hi Wolfgang,

    thank you for your suggestion. We have already implemented a similar interface. But, unfortunately, it is for internal use only (at least for now). We will add this feature to the public API. ETA is 2019v3 - somewhere in late autumn/early winter.

    What you described can be done using “applyThemeToSubTree” predicate except one case: when a theme should not be applied to a parent control, but should apply to its children. And if I understand correctly, this case is important for you.

    If you can’t wait for update, I can offer you a workaround. But I have to admit, it’s not the most elegant =) And this is only a temporary solution, since it may happen that it will stop working with future updates (since the “for internal use only” method should be used here).

    If you’re interested, let me know and I’ll prepare a sample for you.

    Best Regards,

    Nikita Parkhomenko

    WinForms Developer

    GrapeCity, Inc.

  • Posted 12 August 2019, 9:17 am EST

    Hi Nikita,

    sorry, I totally missed your reply…

    I think we don’t understand each other ;-).

    Attached is a small sample which hopefully clarifies my requirement: the form contains a UserControl, which has a textbox whose BackColor should not change.

    I known that I can prevent this using the “applyThemeToSubTree” predicate. But this only works if the Form knows that the control “MyUserControl” contains a non themeable control.

    I request a more flexible approach: no matter on which form “MyUserControl” is placed, it should work without adding additional code to the forms.

    That’s why I suggest an interface like “ICanApplyTheme” which is implemented by parent controls, in my sample by “MyUserControl”, and which prevents theming of child controls.

    NonThemeableControl.zip

    Best regards

    Wolfgang

  • Posted 13 August 2019, 12:24 am EST

    Hi Wolfgang,

    We’re discussing your requirement with the developers [Internal Tracking ID: 382275]. I’ll provide an update as soon as we have anything definite to share with you.

    Thanks,

    Jitender

  • Posted 13 August 2019, 12:29 am EST

    Hi Wolfgang,

    We’ve asked the developers to look into this. I’ll let you know when we get any information from them.

    Thanks,

    Jitender

  • Posted 13 August 2019, 2:49 am EST

    Hi Wolfgang,

    Thank you for your explanation.

    You can implement this behavior even without using any internal methods.

    NonThemeableControl.zip

    I corrected your sample. Check whether this solution satisfies your requirements. Of course, you will have to add additional code to the form, but it does not need to know the information about the control and this solution will work with dynamically created forms and controls.

    Pay attention to the ICanApplyTheme interface, MyTextBox that implements this interface and the predicate that I used in the ApplyThemeToControlTree method. All you need is to use this control instead of the standard one and set its CanApplyTheme property value as ‘False’. Other controls can be implemented in the same way

    And as I described above, this method is suitable for everything except one case: when a theme should not be applied to a parent control, but should apply to its children.

    Please check if it suits you.

    Best Regards,

    Nikita Parkhomenko

    WinForms Developer

    GrapeCity, Inc.

  • Posted 13 August 2019, 3:22 am EST

    Hi Nikita,

    thanks, this should work. I did not think about this quite simple solution ;-).

    But now I have the use case that I don’t have a custom “MyTextBox” class, but MyUserControl contains just a textbox that has a modified BackColor (as it was implemented in my original sample). So only MyUserControl knows that the textbox child control should not be themed. Same might apply to labels and different fore color.

    MyUserControl could implement an interface “ICanApplyTheme” with a method “CanApplyTheme (Control childControl)”. This method is called by C1ThemeController for each control on MyUserControl, and the theme is applied only to the child control if the method returns “true”.

    Of course, those interface implementations can stack: a form might contain UserControls (or TabPages or other custom controls) which implement this interface, and such a UserControl might contain other custom controls with this interface implementation. The “CanApplyTheme” interface method should only be called for the “nearest” parent, but not for all parent controls.

    Do you think it is reasonable to add this code (and the interface) to C1Themes dll?

    Any yesterday I came to another weird requirement: a child control wants to get notified that its theme has changed. My use case was: C1FlexGrid has custom logic for setting the alternate style, e.g. that all rows for a date have the same back color, and the next date row group has alternate style. So, I pick the alternate back color from the theme, but apply it myself to the grid rows (see my question at https://www.grapecity.com/forums/winforms-edition/c1theme-how-to-query-eg-c1).

    For this case, I would need an interface “IThemeWasApplied” or something similar with a method “OnThemeChanged(C1Theme newTheme)”, so that all controls implementing this interface are notified about a theme change.

    I helped myself by doing this notification in the form, as it is only relevant for one grid in the moment. But if we make heavier use of themes, a notification on control level might be more helpful.

    Best regards

    Wolfgang

  • Posted 13 August 2019, 3:59 am EST

    Hi Wolfgang,

    Thank you for your comment.

    About your suggestion of ICanApplyTheme:

    I understand how convenient that would be for you. But inside this “CanApplyTheme (Control childControl)” method, the UserControl also somehow has to check whether the sub control is themeable or not. And this is either the use of the interface (and this is the same as I suggested), or spelled out directly (and this is excuse me not the best solution, but it is the place to be in some situations). Therefore, at the moment this method is somewhat redundant, since this issue can be solved quite simply without it.

    However, thanks to you, we’ve already added IThemeable interface :wink: It will be available in 2019 v3 2019v3 - somewhere in late autumn/early winter. And I’ll discuss this case with the team. Perhaps we can come up with some universal mechanism that will simplify the solution of such cases.

    About OnThemeChanged:

    I agree with you there. It is strange that we ourselves had not thought of :wink: I think the IThemeable interface should contain this method. I will create a request and will try to include it in the 2019v3 development (although to be honest, there is very closely already).

    Thank you again. It's nice to see someone using our themes at such a high level.
    

    Best Regards,

    Nikita Parkhomenko

    WinForms Developer

    GrapeCity, Inc.

  • Posted 14 August 2019, 2:43 am EST

    Thanks, I am awaiting the new version :wink:

    Wolfgang

  • Posted 21 November 2019, 12:08 pm EST

    Hi Nikita,

    just tested with .393. Here is my feedback and my complaints ;-).

    First the complaint: I don’t see a resolution for my requirement for a method “CanApplyTheme (Control childControl)”. You wrote “I’ll discuss this case with the team” - did the team reject my suggestion ;-).

    And not feedback about “IC1Themeable” (by the way: thanks for adding it ;-)):

    My use cases are that I either want to implement the method “IC1Themeable.OnThemeChanged” or “IC1Themeable.AllowThemeChange” (but not both), and “OnThemeChanging” is not relevant for me. But now I have to implement all three methods each time.

    Unfortunately default methods on interfaces are part of C# 8 and not usable with .NET 4.6.

    So the only solution might be to divide these method into three interfaces, each with a single method/property - but this is probably not worth the work. Anyway, I would be glad if you could add this ;-).

    Best regards

    Wolfgang

  • Posted 27 November 2019, 8:42 am EST

    Hi Wolfgang,

    Thank you for testing the latest release build.

    Regarding the above concerns, I am in discussion with the developer and have updated him with your observations & suggestions.

    We shall get back to you with an update on this soon.

    Best wishes,

    Ruchir

  • Posted 28 November 2019, 5:15 am EST

    Hi Wolfgang,

    thanks for your feedback.

    About ICanApplyTheme:

    we have researched your suggestion and have not been able to come up with a solution that would suit us. In addition, we found a few unpleasant difficulties that will face us if we want to add this interface. Sorry about that. We will continue to collect feedback in this direction, as we are interested in getting customers to start using themes more. But I can’t give you an ETA when this feature will be added and in what form.

    Therefore, we cannot provide you with a built-in solution for this issue, but we can help you find a workaround. The current public API is sufficient to implement the requirements. I can prepare another sample for you with your requirements if you are interested (where you don’t need MyTextBox).

    About interface separation:

    You don’t need to implement methods that you don’t need, in the sense that you can leave the method body empty and it won’t break anything:

    // IC1Themeable

    bool IC1Themeable.AllowThemeChange => true;

    void IC1Themeable.OnThemeChanged(string theme) {}

    void IC1Themeable.OnThemeChanging(string theme) {}

    I’m sure you’re aware of that, so it is a question of the number of lines of code? In any case, the separation of interfaces is a common practice, so there is no reason not to do it if it will add convenience. We will break this interface into several. Just need to think about the names ;-).

    Thanks again for your feedback.

    Best Regards,

    Nikita Parkhomenko

    WinForms Developer

    GrapeCity, Inc.

  • Posted 29 November 2019, 5:10 am EST

    Hi Nikita,

    thanks for the feedback.

    I created a small code sample which demonstrates how an interface “ICanApplyThemeToChild” could work in my understanding: two controls with green background are not themed, and I have a deeply nested control hierarchy. See the “ThemeController” class for usage of the interface.

    What do you think about this? Would this approach be possible or did I miss something?

    ICanThemeChildSuggestion.zip

    Anyway, could you create a sample on how to achieve this requirement with the current C1Themes API?

    Best regards

    Wolfgang

  • Posted 2 December 2019, 3:44 am EST

    Hi Wolfgang,

    Thank you for explaining your approach. But unfortunately our difficulties are rather idealogical or related to the internal implementation of C1Themes.

    I have prepared you a sample with the implementation of the required behavior.

    NonThemeableControl2.zip

    Your required assumes that the UserControl knows about the children and to which of them the theme should be applied. I tried to implement two ways:

    1. Create a new interface (IThemeManager) and use it in a ApplyThemeToControlTree method. (see ThemeManager folder)
    2. Drag the C1ThemeControler onto the form and use it as intended. And implement the IC1Themeable interface for the UserControl. (see Themeable folder)

    In both cases, the UserControl will determine to which control the theme should be applied.

    Now when you are not tied to use the ApplyThemeToControlTree method, the second approach is more in line with our vision of themes. In addition, it will work in both run-time and design-time. You can also use the ApplicationTheme to sync all the C1ThemeControllers.

    Let me know if you have any questions or comments.

    Best Regards,

    Nikita Parkhomenko

    WinForms Developer

    GrapeCity, Inc.

  • Posted 2 December 2019, 12:15 pm EST

    Hi Nikita,

    thanks for the sample. You implemented it the other way than I suggested ;-): while I added an interface which prevents theming of a control, in your interface “IThemeManager” the implementor has to start theming himself. Well, this would be also OK for me.

    But I assume “theme.ApplyThemeToObject” just applies the theme to a single control. So, If the control is another custom user control, I would have to call “C1ThemeController.ApplyThemeToControlTree”. Should be possible as it is a static method.

    Will you add this interface to the API, or would I add it to my own code?

    My use case for calling “C1ThemeController.ApplyThemeToControlTree” is that we have forms where the user can dynamically create new tabs. So, those tabs have to be themed when they are created.

    Best regards

    Wolfgang

  • Posted 3 December 2019, 1:54 am EST

    Hi Wolfgang,

    No, we do not plan to add this or similar interface to the API. We will continue to develop the C1Theme to make them more flexible, but nothing in this direction is planned for the near future. Sorry about that. So it is probably the best solution for you to implement such an interface in your code.

    Of course you can use “C1ThemeController.ApplyThemeToControlTree” if it’s convenient for you.

    Thanks again for your feedback. Ask if you have any more questions.

    Best Regards,

    Nikita Parkhomenko

    WinForms Developer

    GrapeCity, Inc.

  • Posted 3 December 2019, 4:22 am EST

    Thanks!

    I will keep this solution in mind when I need it once more.

    Best regards

    Wolfgang

Need extra support?

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

Learn More

Forum Channels