0

I'm trying to create a menu that works with radio buttons. The buttons are graphically prettied by a template. here I would like to display an icon and a text. However, I don't know how I can pass several parameters, so far I only pass the text and have not yet found a way to pass the image.

  <StackPanel Grid.Row="1" Margin="0,10,0,0">
            <RadioButton Content="Dashboard"
                         IsChecked="True"
                         Style="{StaticResource MenuButtonTheme}"/>
            <RadioButton Content="Product"
                         Style="{StaticResource MenuButtonTheme}"/>
            <RadioButton Content="Inventory"
                         Style="{StaticResource MenuButtonTheme}"/>
        </StackPanel>

Style Of the Radiobutton

  <Style BasedOn="{StaticResource {x:Type ToggleButton}}"
       TargetType="{x:Type RadioButton}"
       x:Key="MenuButtonTheme">
    <Style.Setters>
        <Setter Property="Foreground" Value="#FFFFFF"/>
        <Setter Property="FontFamily" Value="/Fonts/#Poppins"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="RadioButton">
                    <Border Background="{TemplateBinding Background}"
                            CornerRadius="5"
                            Margin="5,0,5,0">
                        <Grid VerticalAlignment="Stretch"
                          HorizontalAlignment="Stretch"
                          Height="50"
                          >
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="30"/>
                                    <ColumnDefinition/>
                                </Grid.ColumnDefinitions>
                                <iconPacks:PackIconBoxIcons Kind="SolidPieChartAlt2" 
                                                            VerticalAlignment="Center"
                                                            HorizontalAlignment="Center"
                                                            Margin="10,0,0,0"/>
                            <TextBlock Grid.Column="1" Text="{TemplateBinding Property=Content}"
                                   VerticalAlignment="Center"
                                   FontSize="20"
                                   FontWeight="Regular"
                                   Margin="10,0,0,0"/>
                            </Grid>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="0"/>
    </Style.Setters>
    <Style.Triggers>
        <Trigger Property="IsChecked" Value="true">
            <Setter Property="Background" Value="#212121"/>
            <Setter Property="Foreground" Value="#4169E1"/>

        </Trigger>
    </Style.Triggers>
</Style>

enter image description here

Korte
  • 21
  • 2
  • there are a few ways to parametrize templates. I listed those which I use [in his post](https://stackoverflow.com/a/40663219/1506454). One extra shortcut is make use of `Tag` property. – ASh Dec 28 '21 at 19:32

1 Answers1

0

Foreach particular part of UI in your application, I recommend you to make it a module, that is, a UserContol or ContentControl(recommened). These controls corresponds to View in MVVM, and foreach of them you should add a View Model.

namespace MyNameSpace{
    public class View<T> : ContentControl {
        public T ViewModel {
            get { return (T)GetValue(ViewModelProperty); }
            set { SetValue(ViewModelProperty, value); }
        }
        public static readonly DependencyProperty ViewModelProperty =
            DependencyProperty.Register("ViewModel", typeof(T), typeof(View<T>), new PropertyMetadata());
    }

    public abstract class ViewModel : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged([CallerMemberName] String propertyName = null) {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

If the relative logic is purely UI, then Model is not needed in this case. Your View's xaml should look like this:

<local:View x:TypeArguments="MyAViewModel" x:Name="view"
    x:Class="MyNameSpace.MyAView"
             skip
             xmlns:local="clr-namespace:MyNameSpace">
    <Image Source="{Binding ViewModel.ImageSource,ElementName=view}"/>
</local:View>

Your ViewModel should look like this:

    public class MyAViewModel: ViewModel {
        public AbilityViewModel() {//Constructor with parameter
            //Set the image source here
        }
        private ImageSource imageSource;
        public ImageSource ImageSource{ 
            get => imageSource
            set{
                imageSource = value;
                NotifyPropertyChanged();
            }
        }
    }

In the root element of your UI hierarchy, for example your MainWindow, add your custom contols:

<Window x:Name="window" skip>
    <Grid>
        <local:MyAView ViewModel="{Binding MyAViewModel,ElementName=window}"/>
        <local:MyBView ViewModel="{Binding MyBViewModel,ElementName=window}"/>
    </Grid>
</Window>

You may either do so with adding dependency properies of the MyAViewModel and MyBViewModel to your MainWindow, or just set MyAView's ViewModel in MainWindow's constructor or loaded event. You may create the ViewModel to pass to view, in which ImageSource is initialized in constructor, or change it after its construction by somewhere in your code.

Above codes are just demo, directly written in stackoverflow's webpage and is not tested. You may ask me if there is any problem.

martinrhan
  • 362
  • 1
  • 18