如何避免在菜单中重复XAML块 [英] How to avoid repeating blocks of XAML in a menu

查看:43
本文介绍了如何避免在菜单中重复XAML块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须创建一个菜单.它有10个条目,并且它们之间的差异仅是一个参数.

I have to create a menu. It has 10 entries and they differ by one parameter.

条目1:

<MenuItem Visibility="{Binding MenuSelected.Type, Converter={StaticResource TypeToVisibilityConverter}, ConverterParameter='PAZ', Mode=OneWay}">
   <i:Interaction.Triggers>
      <i:EventTrigger EventName="Click">
         <i:InvokeCommandAction Command="{Binding CmdContextMenu}" CommandParameter="PAZ" />
      </i:EventTrigger>
   </i:Interaction.Triggers>
   <MenuItem.Header>
      <Grid>
         <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
         </Grid.ColumnDefinitions>
         <TextBlock
                                        Grid.Column="0"
                                        HorizontalAlignment="Center"
                                        VerticalAlignment="Center"
                                        FontFamily="Segoe MDL2 Assets"
                                        Foreground="{Binding MenuSelected.Type, Converter={StaticResource TypeToColorConverter}, ConverterParameter='PAZ', Mode=OneWay}"
                                        Text="{Binding MenuSelected.Type, Converter={StaticResource TypeToIconConverter}, ConverterParameter='PAZ', Mode=OneWay}" />
         <TextBlock
                                        Grid.Column="1"
                                        Margin="{StaticResource XSmallLeftMargin}"
                                        HorizontalAlignment="Left"
                                        VerticalAlignment="Center"
                                        Text="PAZ" />
      </Grid>
   </MenuItem.Header>
</MenuItem>

条目2:

<MenuItem Visibility="{Binding MenuSelected.Type, Converter={StaticResource TypeToVisibilityConverter}, ConverterParameter='APP', Mode=OneWay}">
   <i:Interaction.Triggers>
      <i:EventTrigger EventName="Click">
         <i:InvokeCommandAction Command="{Binding CmdContextMenu}" CommandParameter="APP" />
      </i:EventTrigger>
   </i:Interaction.Triggers>
   <MenuItem.Header>
      <Grid>
         <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
         </Grid.ColumnDefinitions>
         <TextBlock
                                        Grid.Column="0"
                                        HorizontalAlignment="Center"
                                        VerticalAlignment="Center"
                                        FontFamily="Segoe MDL2 Assets"
                                        Foreground="{Binding MenuSelected.Type, Converter={StaticResource TypeToColorConverter}, ConverterParameter='APP', Mode=OneWay}"
                                        Text="{Binding MenuSelected.Type, Converter={StaticResource TypeToIconConverter}, ConverterParameter='APP', Mode=OneWay}" />
         <TextBlock
                                        Grid.Column="1"
                                        Margin="{StaticResource XSmallLeftMargin}"
                                        HorizontalAlignment="Left"
                                        VerticalAlignment="Center"
                                        Text="APP" />
      </Grid>
   </MenuItem.Header>
</MenuItem>

正如您所看到的,唯一的区别是 PAZ APP 之间的不同点……其他所有方面都一样.有什么办法可以避免只更改3个字母就重复10次吗?

As you can see, the only difference is between PAZ and APP in different points... and same goes on for all the others. Is there a way I can avoid to repeat it 10 times just changing the 3 letters?

我不想使用代码隐藏功能动态创建菜单...而是从XAML处理它.

I do not want to use code-behind to create the menu dynamically... but to process it from XAML.

推荐答案

根据您的问题,我假定 CmdContextMenu MenuSelected 是主视图模型的属性,而不是单独的菜单项类型.如果不同,则必须相应地修改代码.

From your question I assume that CmdContextMenu and MenuSelected are properties on your main view model and not in a separate menu item type. If this is different, you have to adapt the code accordingly.

为了删除冗余代码,请在视图模型中为菜单项创建一个集合.

In order to remove the redundant code, create a collection for your menu items in your view model.

public class MyMainViewModel : INotifyPropertyChanged
{
   public IEnumerable<string> MyTypes { get; } = new List<string>
   {
      "PAZ",
      "APP"
   };

   // ...other properties and methods (like "CmdContextMenu" and "MenuSelected" I Assume).
}

接下来,您必须更改值转换器,因为 <可以绑定多个值的code> IMultiValueConverter .调整所有转换器以实现 IMultiValueConverter .这是一个转换器外观的示例.当然,这取决于您的实现.本质上,使用 values 数组访问绑定值.

Next, you have to change the value converters, because the ConverterParameter is not a dependency property and cannot be bound. Instead, you can use IMultiValueConverters that can bind multiple values. Adapt all of your converters to implement IMultiValueConverter. Here is an example of how a converter could look like. Of course, it depends on your implementation. In essence, use the values array to access bound values.

public class TypeToVisibilityConverter : IMultiValueConverter
{
   public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
   {
      return values[0].Equals(values[1]) ? Visibility.Visible : Visibility.Collapsed;
   }

   public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
   {
      throw new NotImplementedException();
   }
}

接下来,为菜单项的标题创建一个数据模板.如您所见,绑定被 MultiBinding 替换,后者使用 IMultiValueConverter 作为 Converter .

Next, create a data template for the header of your menu items. As you can see, the bindings are replaced with MultiBindings that use an IMultiValueConverter as Converter.

每个块中的第一个绑定是一个 RelativeSource 绑定,用于访问父 Menu 的数据上下文,因为我假设 MenuSelected 属性是在主视图模型上定义的.其他空绑定将绑定到当前菜单项的数据上下文,该菜单项是 MyTypes 集合中的项.

The first binding in each block is a RelativeSource binding to access the data context of the parent Menu, because I assume that the MenuSelected property is defined on your main view model. The other empty bindings will bind to the data context of the current menu item, which is an item from the MyTypes collection.

<DataTemplate x:Key="MyMenuItemHeaderTemplate" DataType="{x:Type system:String}">
   <Grid>
      <Grid.ColumnDefinitions>
         <ColumnDefinition Width="Auto" />
         <ColumnDefinition Width="*" />
      </Grid.ColumnDefinitions>
      <TextBlock Grid.Column="0"
                 HorizontalAlignment="Center"
                 VerticalAlignment="Center"
                 FontFamily="Segoe MDL2 Assets">
         <TextBlock.Foreground>
            <MultiBinding Converter="{StaticResource TypeToColorConverter}">
               <Binding Path="DataContext.MenuSelected.Type" RelativeSource="{RelativeSource AncestorType={x:Type Menu}}" Mode="OneWay"/>
               <Binding/>
            </MultiBinding>
         </TextBlock.Foreground>
         <TextBlock.Text>
            <MultiBinding Converter="{StaticResource TypeToIconConverter}">
               <Binding Path="DataContext.MenuSelected.Type" RelativeSource="{RelativeSource AncestorType={x:Type Menu}}" Mode="OneWay"/>
               <Binding/>
            </MultiBinding>
         </TextBlock.Text>
      </TextBlock>
      <TextBlock Grid.Column="1"
                 Margin="{StaticResource XSmallLeftMargin}"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Center"
                 Text="{Binding}"/>
   </Grid>
</DataTemplate>

创建使用此数据模板的新标题项目样式. Visibility (可见性)还使用如上所述的多值转换器.无需使用事件触发器,只需将命令直接分配给菜单项并传递 CommandParameter (绑定到当前菜单项的数据上下文)即可.

Create a new header item style that uses this data template. The Visibility also uses a multi-value converter as above. Instead of using an event trigger, you can simply assign the command to the menu item directly and pass a CommandParameter, which is bound to the data context of the current menu item.

<Style x:Key="MyMenuItemStyle" TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}">
   <Setter Property="HeaderTemplate" Value="{StaticResource MyMenuItemHeaderTemplate}"/>
   <Setter Property="Visibility">
      <Setter.Value>
         <MultiBinding Converter="{StaticResource TypeToVisibilityConverter}">
            <Binding Path="DataContext.MenuSelected.Type" RelativeSource="{RelativeSource AncestorType={x:Type Menu}}" Mode="OneWay"/>
            <Binding/>
         </MultiBinding>
      </Setter.Value>
   </Setter>
   <Setter Property="Command" Value="{Binding DataContext.CmdContextMenu, RelativeSource={RelativeSource AncestorType={x:Type Menu}}}"/>
   <Setter Property="CommandParameter" Value="{Binding}"/>
</Style>

最后,创建一个 Menu 并绑定 MyTypes 集合以及样式.

Finally, create a Menu and bind the MyTypes collection, as well as the style.

<Menu ItemsSource="{Binding MyTypes}" ItemContainerStyle="{StaticResource MyMenuItemStyle}"/>

这篇关于如何避免在菜单中重复XAML块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆