I’m diving head-first into Eto.Forms and have a few questions about styling of various UI elements. The aim is to create a tabbed interface with a few collapsible element groups to enhance user interaction.
How can I change the color and thickness of all borders? Can’t find it anywhere in TabControl, TabPage, or Panel. Ideally, I’d like to remove the dividing line between the TabControl elements and the panel whose visibility they toggle.
How can I change the font of the Expander.Header element? It’s possible on a GroupBox as illustrated above.
Changing Expander.BackgroundColor and Expander.Header.BackgroundColor doesn’t seem to have any effect and forces the default grey color no matter what the above are set to.
Is there a style inheritance hierarchy, which one needs to be aware of to control these elements’ appearance?
Could you shed some light at it @curtisw?
Sorry for the slow response. You can certainly access all of the visual styling at least on Windows (where Eto uses WPF), since Eto.Forms is simply an abstraction of WPF on Windows, and AppKit on macOS.
Controls on AppKit/macOS are generally less flexible on what you can change, and with WPF there is a lot of flexibility but it can be much more difficult to do as you sometimes have to use XAML styles.
Hopefully these answers help:
To change the color and thickness of borders of a TabControl, you’ll have to create a WPF style for its TabItem and apply that to that WPF control.
The Expander.Header is a Control, so you can usually just do:
myExpander.Header = new Label { Font = SystemFonts.Bold(12), Text = "My Text" }
Unfortunately, we have customized the Expander specifically for Rhino to change its style, and it doesn’t allow you to change the font directly in the same way. I’ve created RH-67888 to look into that. In the meantime, this might work better when working in a panel:
myExpander.Header = new Panel { Content = new Label { Font = .., Text = "My Text" }
or
myExpander.Header = "My Text";
if (myExpander.Header is Label label)
{
label.Font = ...
}
It should be possible to set the background color of an Expander, but I think what you might be running into is that Rhino itself applies styles and themes to pretty much all Eto controls when hosted in a Rhino Panel (vs. using a Form or Dialog). We have some internal helper methods to turn this off in certain cases, but we have not exposed this API yet. I’ve logged RH-67885 to make it public for 3rd party devs. It should hopefully land in 7.17 soon.
As for the GroupBox border thickness, that is working for me. Are you sure your GroupBoxHandler style is being added before you have myGroupBox.Style = "myBox";? Perhaps it needs to be moved, preferably in a static constructor or when your plugin is loaded.
If you want full control of your visual style, I’d recommend also looking into using a Drawable in which you can paint any of the elements yourself in its Paint event. Rhino’s custom Expander for example uses that, along with many other UI elements.
m_holder.Styles.Add<Rhino.UI.Controls.CollapsibleSectionContainerHandler>(null, c =>
{
Eto.Forms.Label title = c.Header as Eto.Forms.Label;
if (title != null)
title.Font = new Eto.Drawing.Font("Arial", 24, Eto.Drawing.FontStyle.Italic, Eto.Drawing.FontDecoration.Underline);
});
Thanks for exposing the Background color controls in Rhinocommon! It’s quite confusing to work with form styling without understanding Rhino’s inheritance hierarchy and having handy overrides to customize things. For now, we managed to unify background colors of all controls by a global style definition:
No success. This only compiles up to Rhinocommon 7.13.21348.13001, later versions throw the following errors:
Severity
Code
Description
Error
CS0311
The type ‘Eto.Wpf.Forms.Controls.GroupBoxHandler’ cannot be used as type parameter ‘TWidget’ in the generic type or method ‘Style.Add(string, StyleWidgetHandler)’. There is no implicit reference conversion from ‘Eto.Wpf.Forms.Controls.GroupBoxHandler’ to ‘Eto.Widget’.
Error
CS0012
The type ‘WidgetHandler<,>’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘Eto, Version=2.6.0.0, Culture=neutral, PublicKeyToken=null’.
I’m referencing a NuGet Eto.Platform.Wpf 2.6.0 package. This automatically adds it’s own version of Eto.dll on compile. I then delete it in post-build events like so:
Absolutely, I’ll try to cook something up for you.
Great, that looks good. We were a little overzealous on applying background colours to all controls, as it really is only needed for the main panel. Either way though, the new APIs should help get you to a blank slate.
While you can do this, you must not include any of the associated assemblies, such as Eto.dll and Eto.Wpf.dll. An easier way is to use the RhinoWindows nuget package, which includes Eto.Wpf.
This was the missing piece of the puzzle! Switching to the RhinoWindows nuget package made the handler approach work. Now, we can override the appearance of individual elements like so:
Eto.Style.Add<Eto.Wpf.Forms.Controls.GroupBoxHandler>(null, h => {
h.Control.BorderThickness = new System.Windows.Thickness(2);
h.Control.BorderBrush = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(255, 0, 255));
});
@curtisw, how would you approach developing for Mac, though? The whole idea behind using Eto was to have a cross-platform UI. I was hoping to use these style overrides only on Windows and fall back to defaults on OSX. This made sense while referencing RhinoCommon. Doesn’t switching to RhinoWindows invalidate this approach?
If you want to include windows-specific functionality you can do it a number of ways. First would be to compile your plugin specifically for Windows and for Mac. Yak/PackageManager packages support having platform specific packages.
The second approach would be to move your platform-specific code to a separate assembly and only load/execute that code when running on that platform. This is basically what Eto does, which allows you to create your own extended versions of controls like the GroupBox, or just roll your own thing to execute the styles.
hi mariusz, looks like you kind of solved this yourself in your terrain plugin. I wonder when you will share some of the epic Eto UI magic you’ve done for that?
[EDIT] I just scrolled up to the top to see where it all started a little bit more than a year ago:
It’s been a fun journey ever since and @Wiley and I have learned heaps in the process. Let me know if the community would be interested in us sharing our experience with UI development. We could cook something up maybe.