Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Derive from IconElement or IconSourceElement in UWP

I'm trying to create the same custom symbol icon control as MS SymbolIcon, which will get the enum symbol values as input, and the equivalent path data value will be retrieved from the dictionary<Symbol, string> collection. But the symbol icon class inherited from IconElement and the same below issue faced in my application.

'IconElement does not take a constructor that takes 0 arguments'

Derive from IconElement in UWP

but I have marked my constructor as extern and enclosed with semicolon to resolve the constructor issue.

public class CustomSymbolIcon : IconElement
{ 
   public extern CustomSymbolIcon(); 
}

But my question is, I can get input from the end user as Symbol Enum and retrieved equivalent path geometry based on input from the stored dictionary. But I couldn't bind the path geometry to the path element(Targeted Custom icon class)and I can't write the template style for this class. Because IconElement was derived from the framework element.

I can achieve these all with control class , but I can't use this inside the <NavigationView.Icon> (its a IconElement base) tag due to base class.

public class SymbolToIconConversion : Control //IconElement instead of control
{
    internal static Dictionary<Symbol, string> enumValuesCollection = new Dictionary<Symbol, string>();

    public SymbolToIconConversion()
    {
        this.DefaultStyleKey = typeof(SymbolToIconConversion);
        PopulateEnumCollection();
    }

    public static Dictionary<Symbol, string> EnumValuesCollection
    {
        get { return enumValuesCollection; }
        set { enumValuesCollection = value; }
    }

    internal void PopulateEnumCollection()
    {
        enumValuesCollection.Add(Symbol.Accept, "M0,4 5,9 9,0 4,5");
        enumValuesCollection.Add(Symbol.Close, "F1 M 22,12L 26,12L 26,22L 36,22L 36,26L 26,26L 26,36L 22,36L 22,26L 12,26L 12,22L 22,22L 22,12 Z");
        enumValuesCollection.Add(Symbol.Save, "M0,4 5,9 9,0 4,5");
        enumValuesCollection.Add(Symbol.Add, "M0,5 H10 M5,5 V10Z");
    }

    public Symbol Symbol
    {
        get { return (Symbol)GetValue(SymbolProperty); }
        set { SetValue(SymbolProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Symbol.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SymbolProperty =
          DependencyProperty.Register("Symbol", typeof(Symbol), typeof(SfSymbolIcon), new PropertyMetadata(typeof(Symbol), new PropertyChangedCallback(OnSymbolChanged)));      

    internal Geometry Geometry
    {
        get { return (Geometry)GetValue(GeometryProperty); }
        set { SetValue(GeometryProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Geometry.  This enables animation, styling, binding, etc...
    internal static readonly DependencyProperty GeometryProperty =
        DependencyProperty.Register("Geometry", typeof(Geometry), typeof(SymbolToIconConversion), new PropertyMetadata(null));

    private static void OnSymbolChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        SymbolToIconConversion symbolIcon = d as SymbolToIconConversion;
        if (symbolIcon != null)
        {
            foreach (var value in EnumValuesCollection)
            {
                if (symbolIcon.Symbol == value.Key)
                {
                    symbolIcon.Geometry = (Geometry)XamlBindingHelper.ConvertValue(typeof(Geometry), value.Value);
                    return;
                }
            }
        }
    }

 <Style TargetType="core:SymbolToIconConversion">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="core:SymbolToIconConversion">
                <Viewbox x:Name="ContentViewbox" AutomationProperties.AccessibilityView="Raw" HorizontalAlignment="Stretch" Height="{ThemeResource AppBarButtonContentHeight}" Margin="{ThemeResource AppBarButtonContentViewboxCollapsedMargin}">
                    <Path x:Name="Content" 
                          Width="{Binding Width, RelativeSource={RelativeSource Mode=TemplatedParent}}" 
                          Height="{Binding Height, RelativeSource={RelativeSource Mode=TemplatedParent}}" 
                          Fill="{Binding Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}" 
                          Data="{Binding Geometry, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
                </Viewbox>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
  1. How to initialize dictionary in constructor of custom class? - Need to populate the dictionary when control loaded. I can't call this method in extern constructor.
  2. If possible, path geometry retrieval using symbol achieved by Dictionary<Symbol, String> collection populated. Is this efficient way?,Bcz it leads to key already added in collection issue when initialize the control at second time. Please suggest alternate ways to achieve this.
  3. How can write style for framework element? I need to bind the Path data in control style. But it doesn't have template property.

Can anyone suggest how to achieve this?

like image 533
Kanniyappan P Avatar asked Nov 15 '22 03:11

Kanniyappan P


1 Answers

Derive from IconElement or IconSourceElement in UWP

I'm afraid you can't make CustomSymbolIcon that inherit IconElement, and IconElement does not provide method to set ControlTemplate, for your scenario, we suggest you use custom Datatemplate to replace NavigationViewItem like the following

<NavigationView.MenuItemTemplate>
    <DataTemplate>
        <Grid Width="{Binding ElementName=nvSample, Path=OpenPaneLength}" HorizontalAlignment="Stretch">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <local:SymbolToIconConversion Symbol="Accept"  VerticalAlignment="Center"/>
            <StackPanel
                Grid.Column="1"
                Margin="45,0,10,0"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Center">
                <TextBlock x:Name="Header" Text="Header" />
                <TextBlock x:Name="Line1" Text="TheFirstLine" />
            </StackPanel>
        </Grid>
    </DataTemplate>
</NavigationView.MenuItemTemplate>
like image 156
Nico Zhu - MSFT Avatar answered Dec 04 '22 03:12

Nico Zhu - MSFT