【问题标题】:Binding HeaderTemplate in MVVM Menu在 MVVM 菜单中绑定 HeaderTemplate
【发布时间】:2015-09-20 05:14:24
【问题描述】:

我有一个 MVVM 样式的菜单,它使用 2 个视图模型和一个样式完成:

视图模型:

public class CommandViewModel : ViewModelBase
{
    private bool _isOpen;
    private IEnumerable<object> _items;
    private UIElement _placementTarget;



    /// <summary>
    /// the command itself
    /// </summary>
    public ICommand Command { get; set; }

    /// <summary>
    /// parameter object for the command
    /// </summary>
    public Object CommandParameter { get; set; }

    /// <summary>
    /// header string for the command, e.g. in menus
    /// </summary>
    public string Header { get; set; }

    /// <summary>
    /// oprional Tooltip for the command, e.g. on buttons
    /// </summary>
    public string Tooltip { get; set; }

    /// <summary>
    /// optional icon for the command, e.g. on buttons or in menus
    /// </summary>
    public ControlTemplate Icon { get; set; }


    /// <summary>
    /// optional item list. e.g. submenu entries.
    /// For a submenu set the command to null and fill the Items list with CommandViewModels or other ViewModels you have a template for
    /// </summary>
    public IEnumerable<Object> Items
    {
        get { return _items; }
        set
        {
            _items = value;
            Command = new RelayCommand<UIElement>((param) =>
            {
                PlacementTarget = param;
                IsOpen = true;
            });
        }
    }


    public bool IsOpen
    {
        get
        {
            return _isOpen;
        }
        set
        {
            _isOpen = value;
            RaisePropertyChanged(() => IsOpen);
        }
    }


    public virtual bool IsSeparator { get { return false; } }


    public UIElement PlacementTarget
    {
        get { return _placementTarget; }
        set
        {
            _placementTarget = value;
            RaisePropertyChanged(() => PlacementTarget);
        }
    }
}

分隔符:

public class SeparatorViewModel : CommandViewModel
{
    public override bool IsSeparator
    {
        get { return true; }
    }
}

风格:

<Style TargetType="MenuItem" BasedOn="{StaticResource {x:Type MenuItem}}" x:Key="MvvmMenuItemStyle">
    <Setter Property="Header" Value="{Binding Header}"/>
    <Setter Property="ItemsSource" Value="{Binding Items}"/>
    <Setter Property="Command" Value="{Binding Command}"/>
    <Setter Property="CommandParameter" Value="{Binding CommandParameter}"/>
    <Setter Property="ToolTip" Value="{Binding Tooltip}"/>
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsSeparator}" Value="true">
            <DataTrigger.Setters>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Rectangle Height="1" Fill="{StaticResource WindowButtonsBackground}" Margin="3,5"/>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </DataTrigger.Setters>
        </DataTrigger>
    </Style.Triggers>
</Style>

用法:

<MenuItem Header="Device" ItemsSource="{Binding DevicesMenu}" Visibility="{Binding IsDevicesMenuVisible, Converter={StaticResource BoolToVisConverter}}">
    <MenuItem.Resources>
        <Style TargetType="MenuItem" BasedOn="{StaticResource MvvmMenuItemStyle}"/>
    </MenuItem.Resources>
</MenuItem>

我将我的(顶部)菜单项的项目绑定到一个 CommandViewModel 列表,该列表可以有子项、标题、命令、CommandParameter 等... IsOpen Prop 用于当我将它与 ContextMenus 一起使用时,这里不是这种情况。

到目前为止效果很好。

现在我想为每个条目添加和图标。我以为我可以在我的样式中添加一个 HeaderTemplate,它显示图标和标题文本,但它不起作用,什么也没显示。

这是我添加到样式中的 HeaderTemplate 设置器:

    <Setter Property="HeaderTemplate">
        <Setter.Value>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <ContentControl Template="{Binding Icon}" Width="26"/>
                    <TextBlock Text="{Binding  Header}" />
                </StackPanel>
            </DataTemplate>
        </Setter.Value>
    </Setter>

注意:我的图标是 ControlTemplate,其中包含 XAML 中的矢量图形,因此我不能使用 MenuItem 的“图标”属性。一旦我将 HeaderTemplate 添加到样式中,菜单条目就不会显示文本和图标。我知道应用了 HeaderTemplate,因为如果我增加图标 ContentControl 的宽度(例如从 26 到 260),我的菜单会变得更宽。这意味着我在 HeaderTemplate 中的绑定存在问题。

有人发现问题了吗?

【问题讨论】:

    标签: c# wpf mvvm


    【解决方案1】:

    图标和标题的绑定不在可视化树中,在那里可以轻松访问数据上下文(需要继承 VM 的数据上下文)和其他项目。绑定需要改为相对源路径。

    这是用于访问具有 VM 的主要数据上下文的近似路径:

    Text="{Binding Header, 
                   RelativeSource={RelativeSource FindAncestor,
                                   AncestorType={x:Type Page}}}"/>
    

    【讨论】:

    • 很好,谢谢!这就是使它起作用的原因:Text="{Binding DataContext.Header, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MenuItem}}}"。它也可以在没有DataContext. 的情况下工作,但它会绑定到 MenuItem 的 Header-Property 而不是 ViewModel 的 Prop。
    • @JCH2k 有一些控件无法访问主 VM,因此对于其他控件/模板,必须牢记这一技巧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2019-07-08
    • 2010-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多