Hi,@essamce. I can't reproduce your problem. You could try modifying your code by referring to the example below. Please let me know if there are questions.
Create a custom IValueConverter that converts a string to a Style. In the converter, you can define the mapping between the string values and the corresponding Style resources.
In your XAML, bind the Style property of the MenuItem to the StyleName property using the converter.
Create a custom IValueConverter class to convert the StyleName string to a Style:
public class StyleNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string styleName && Application.Current.TryFindResource(styleName) is Style style)
{
return style;
}
return DependencyProperty.UnsetValue; // Return an unset value if the style is not found.
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Add the StyleNameConverter to XAML resources:
<Window.Resources>
<local:StyleNameConverter x:Key="styleNameConverter" />
</Window.Resources>
Bind the MenuItem.Style property to the StyleName property using the converter:
<MenuItem Header="{Binding Name}"
Command="{Binding MenuItemCmd}"
CommandParameter="{Binding}"
Style="{Binding StyleName, Converter={StaticResource styleNameConverter}}">
</MenuItem>
In this example, the StyleNameConverter is used to convert the StyleName property (a string) to a Style. It does this by attempting to find a Style resource in the application's resources with the name specified in StyleName. If it finds a matching Style, it returns that Style; otherwise, it returns an unset value.
Make sure you have defined your Style resources in your XAML resources or in your application's resource dictionary, and the StyleName property in your data source matches the names of these Style resources.
Update:
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<Window.Resources>
<Style x:Key="DefaultMenuItemStyle" TargetType="{x:Type MenuItem}">
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="LightGreen" />
<Setter Property="Command" Value="{Binding MenuItemCmd}"/>
</Style>
<Style x:Key="Style1" TargetType="{x:Type MenuItem}">
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="pink" />
<Setter Property="Command" Value="{Binding Command}"/>
</Style>
<Style x:Key="Style2" TargetType="{x:Type MenuItem}">
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="LightBlue" />
<Setter Property="Command" Value="{Binding Command}"/>
</Style>
<local:MenuItemStyleSelector x:Key="ItemStyleSelector" DefaultStyle="{StaticResource DefaultMenuItemStyle}"
Style1="{StaticResource Style1}"
Style2="{StaticResource Style2}" />
</Window.Resources>
<Grid>
<StackPanel>
<Menu DockPanel.Dock="Top" ItemsSource="{Binding MenuItems}" ItemContainerStyleSelector="{StaticResource ItemStyleSelector}">
<Menu.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding Path=MenuItems}">
<TextBlock Text="{Binding Header}"/>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>
</Menu>
</StackPanel>
</Grid>
Codebedhind:
public class MenuItemStyleSelector : StyleSelector
{
public Style DefaultStyle { get; set; }
public Style Style1 { get; set; }
public Style Style2 { get; set; }
public override Style SelectStyle(object item, DependencyObject container)
{
if (item is MenuItemViewModel menuItem)
{
switch (menuItem.StyleName)
{
case "Style1":
return Style1;
case "Style2":
return Style2;
default:
return DefaultStyle;
}
}
return base.SelectStyle(item, container);
}
}
public class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<MenuItemViewModel> MenuItems { get; set; }
public ViewModel()
{
MenuItems = new ObservableCollection<MenuItemViewModel>
{
new MenuItemViewModel { Header = "Alpha" ,Level=0,StyleName="Style2" },
new MenuItemViewModel { Header = "Beta",Level=1,StyleName="Style2",
MenuItems = new ObservableCollection<MenuItemViewModel>
{
new MenuItemViewModel { Header = "Beta1",Level=1 ,StyleName="Style1"},
new MenuItemViewModel { Header = "Beta2",Level=1, StyleName="Style1",
MenuItems = new ObservableCollection<MenuItemViewModel>
{
new MenuItemViewModel { Header = "Beta1a" ,Level=2,StyleName="Style1",},
new MenuItemViewModel { Header = "Beta1b" ,Level=2,}
}
},
new MenuItemViewModel { Header = "Beta3",Level=0,StyleName="Style2", }
}
},
new MenuItemViewModel { Header = "Gamma",Level=1 }
};
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
public class MenuItemViewModel : INotifyPropertyChanged
{
public string Header { get; set; }
public ObservableCollection<MenuItemViewModel> MenuItems { get; set; }
private string _style;
public string StyleName
{
get => _style;
set
{
_style = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public int Level { get; set; }
private readonly ICommand _command;
public MenuItemViewModel()
{
_command = new MyCommand(Execute);
}
public ICommand Command
{
get
{
return _command;
}
}
private void Execute()
{
MessageBox.Show("Clicked at " + Header);
}
}
public class MyCommand : ICommand
{
private readonly Action _action;
public MyCommand(Action action)
{
_action = action;
}
public void Execute(object o)
{
_action();
}
public bool CanExecute(object o)
{
return true;
}
public event EventHandler CanExecuteChanged
{
add { }
remove { }
}
}
The result:
If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.