First of all I must say I can't thank you enough for all the time and effort that your MahApps projects had saved me in my projects.
I've got a suggestion on API design of this project. The main idea came to my mind by looking at how we use Brush, Brushes classes with Foreground property on a control. Through years I've learned that using generic classes along with xaml is not good idea... It will make headaches for the developer down the road... Like having you defined different styles with exactly same xaml code for different TKind in PackIconBase... The following classes are just for demonstration of the idea so it will be easier to understand.
Design
The first class stores the icon data (It's like Brush class or even Color class, read on and you'll find out why). It can even contain other properties like the preferred Brush to draw it with, which can be ignored when it is null (In IconPresenter control template) and the Foreground of IconPresenter would be used instead.
[ContentProperty("PathData")]
public class IconData : Freezable
{
public static IconData Empty;
static IconData()
{
Empty = new IconData();
}
public IconData()
{
}
public IconData(string pathData)
{
PathData = pathData;
}
private static readonly DependencyProperty PathDataProperty = DependencyProperty.Register(
nameof(PathData),
typeof(string),
typeof(IconData),
new PropertyMetadata(null));
[Bindable(true), Category("Appearance")]
public string PathData
{
get => (string) GetValue(PathDataProperty);
set => SetValue(PathDataProperty, value);
}
protected override Freezable CreateInstanceCore()
{
return new IconData();
}
}
The next class is an example of our libraries of icons (like Brushes class but for Modern icons).
And the last one is the control which hosts the icon.
public class IconPresenter : Control
{
private static readonly DependencyProperty DataProperty = DependencyProperty.Register(
nameof(Data),
typeof(IconData),
typeof(Icon),
new PropertyMetadata(null));
[Bindable(true), Category("Appearance")]
public IconData Data
{
get => (IconData) GetValue(DataProperty);
set => SetValue(DataProperty, value);
}
}
In my initial search I couldn't find a way to implement some kind of converter in designer to use strings instead of '{x:Static icons:ModernIcons.Cupcake}' just like we use 'Red' in a foreground property. But even though I could find one, I would definitely not find a way to have intellisense for that.
The developer can even have their own icons defined and use it in the same manner by StaticResource.
We can define an XSD file and a couple of corresponding XML files for each icon pack. Then have a T4 text template to generate classes. The resulting solution structure will be much cleaner and easier to maintain.
NuGet
We would have MahApps.Metro.IconPacks.Core which contains the IconData and IconPresenter classes. And a separate package for each icon pack like MahApps.Metro.IconPacks.Modern which contain classes like ModernIcons. And another package MahApps.Metro.IconPacks which have dependency on all of the mentioned packages.
Browser
For browser application compatibility we can use attributes on static properties of the icon pack classes (For name, description, tags etc.)
Advantages
Cleaner and simpler resulting solution structure which is easier to maintain
It is more resource dictionary friendly in expandability aspect.
We have just one IconPresenter class across application to have its default style set.
Developers can easily define preferred brushes for icons (They are not a simple shape).
Developers can use their custom icons along with our predefined icons in the same manner.
If developers wants to organize their used icons in an application, They can have their own icons repository class defined. And this way they can easily switch between icons for an specific purpose.
public static class ApplicationIcons
{
private static readonly object AppIconKey = new object();
private static readonly object NewKey = new object();
private static readonly IDictionary<object, IconData> Icons = new Dictionary<object, IconData>
{
{AppIconKey, ModernIcons.Cupcake},
{NewKey, MaterialIcons.PlusCircleOutline}
};
public static IconData AppIcon => Icons[AppIconKey];
public static IconData New => Icons[NewKey];
}
Further discussion
We can even forget about the ModernIcons and similar classes and add resource dictionaries for different icon packs and add another property named BasedOn on IconData to help the developer have an alternative solution for the ApplicationIcons class discussed above (If you prefer xaml based solutions for UI problems). But I like it more in C# manner, you know, it's a library and other people shouldn't be able to modify it easily. But this doesn't mean having BasedOn property is wrong. And of course we should handle possible loops in BasedOn parents. Or maybe, we can have another class named Icon which is responsible for storing things like Fill brush along with IconData (I like this idea more).
Summary
So suggested classes and their responsibilities are as following:
IconData: Storing path data of the icon
MaterialIcons: Storing IconData of the known icons in each icon pack
IconPresenter: A control which shows the icon
Icon**: Storing other info about icon like Fill brush along with IconData. An IconData must be easily convertable to an Icon. If defined IconPresenter would use this instead of IconData. So it's kinda like Brush class and IconData is kinda like Color class.
** Additionally suggested, but it would be nice to have something like this.
And at the end I must say fixing FlowDirection in the default style (as it is now) for hosting controls is a bad idea. Sometimes we want the icon to adapt the hosting window's FlowDirection... For example an arrow for the GO button. By overriding its FlowDirection in the default style it doesn't inherit its value from its parent container anymore so it has to be maintained manually and that is definitely a problem. By using suggested IconData (Or Icon) class we can overcome this problem too, but again, I strongly advise against it to have it hard-coded inside the library (One can use the alternative suggested approach in ApplicationIcons class for their specific requirement)
I'm open to any kind of discussion/suggestion about this idea, and in ways which it is not practical. And of course I'm willing to help in implementing it because I don't think it takes more than couple of weekends.
First of all I must say I can't thank you enough for all the time and effort that your MahApps projects had saved me in my projects. I've got a suggestion on API design of this project. The main idea came to my mind by looking at how we use Brush, Brushes classes with Foreground property on a control. Through years I've learned that using generic classes along with xaml is not good idea... It will make headaches for the developer down the road... Like having you defined different styles with exactly same xaml code for different TKind in PackIconBase... The following classes are just for demonstration of the idea so it will be easier to understand.
Design
The first class stores the icon data (It's like Brush class or even Color class, read on and you'll find out why). It can even contain other properties like the preferred Brush to draw it with, which can be ignored when it is null (In IconPresenter control template) and the Foreground of IconPresenter would be used instead.
The next class is an example of our libraries of icons (like Brushes class but for Modern icons).
And the last one is the control which hosts the icon.
Usage
In my initial search I couldn't find a way to implement some kind of converter in designer to use strings instead of '{x:Static icons:ModernIcons.Cupcake}' just like we use 'Red' in a foreground property. But even though I could find one, I would definitely not find a way to have intellisense for that.
The developer can even have their own icons defined and use it in the same manner by StaticResource.
And then
Implementation
We can define an XSD file and a couple of corresponding XML files for each icon pack. Then have a T4 text template to generate classes. The resulting solution structure will be much cleaner and easier to maintain.
NuGet
We would have MahApps.Metro.IconPacks.Core which contains the IconData and IconPresenter classes. And a separate package for each icon pack like MahApps.Metro.IconPacks.Modern which contain classes like ModernIcons. And another package MahApps.Metro.IconPacks which have dependency on all of the mentioned packages.
Browser
For browser application compatibility we can use attributes on static properties of the icon pack classes (For name, description, tags etc.)
Advantages
If developers wants to organize their used icons in an application, They can have their own icons repository class defined. And this way they can easily switch between icons for an specific purpose.
Further discussion
We can even forget about the ModernIcons and similar classes and add resource dictionaries for different icon packs and add another property named BasedOn on IconData to help the developer have an alternative solution for the ApplicationIcons class discussed above (If you prefer xaml based solutions for UI problems). But I like it more in C# manner, you know, it's a library and other people shouldn't be able to modify it easily. But this doesn't mean having BasedOn property is wrong. And of course we should handle possible loops in BasedOn parents. Or maybe, we can have another class named Icon which is responsible for storing things like Fill brush along with IconData (I like this idea more).
Summary
So suggested classes and their responsibilities are as following:
** Additionally suggested, but it would be nice to have something like this.
And at the end I must say fixing FlowDirection in the default style (as it is now) for hosting controls is a bad idea. Sometimes we want the icon to adapt the hosting window's FlowDirection... For example an arrow for the GO button. By overriding its FlowDirection in the default style it doesn't inherit its value from its parent container anymore so it has to be maintained manually and that is definitely a problem. By using suggested IconData (Or Icon) class we can overcome this problem too, but again, I strongly advise against it to have it hard-coded inside the library (One can use the alternative suggested approach in ApplicationIcons class for their specific requirement)
I'm open to any kind of discussion/suggestion about this idea, and in ways which it is not practical. And of course I'm willing to help in implementing it because I don't think it takes more than couple of weekends.