C# 对Mahapps Metro HamburgerMenuIconItem的数据模板应用不同的绑定
我在MVVM WPF应用程序中使用Hamburger菜单,并使用DataTemplate将Badge控件应用于每个菜单项,如下所示:(摘自)C# 对Mahapps Metro HamburgerMenuIconItem的数据模板应用不同的绑定,c#,wpf,data-binding,mahapps.metro,C#,Wpf,Data Binding,Mahapps.metro,我在MVVM WPF应用程序中使用Hamburger菜单,并使用DataTemplate将Badge控件应用于每个菜单项,如下所示:(摘自) ` ` 这很好,但这会将相同的值应用于所有菜单项-在本例中,我绑定到MessagingMainViewModel(包含HamburgerMenu控件标记的视图的视图模型)中名为TestCount的属性 ` ...` 每个菜单项都是一个视图,有自己的视图模型,我想绑定到ChatViewModel和InboxViewModel(但不是ComposeView
`
`
这很好,但这会将相同的值应用于所有菜单项-在本例中,我绑定到MessagingMainViewModel(包含HamburgerMenu控件标记的视图的视图模型)中名为TestCount的属性
`
...`
每个菜单项都是一个视图,有自己的视图模型,我想绑定到ChatViewModel和InboxViewModel(但不是ComposeViewModel)中的一个公开属性,例如,一个名为UnreadCount的属性。我没有MessagingMainViewModel中的子视图模型(因为到目前为止应用程序中还没有需要)
我知道如何绑定到MessagingMainViewModel上的属性(如上面的DataTemplate代码所示),但找不到访问“子”视图的viewmodel的方法-更不用说在DataTemplate中使用它了。这可能吗?谢谢 您在
标记
-属性中设置了内容
。我们可以在数据模板
中使用它来访问标记
-对象中的任何内容。您说您的标记是一个UserControl
,因此我们可以访问它的DataContext
下面是一个示例,假设您拥有的每个视图的属性都相同。如果没有,则需要使用模板选择器
:
为了防止任何人遇到类似的问题,我使用Tag属性来访问相关的视图模型和属性,并实现了DataTemplateSelector,以便在是否显示badge/count控件之间进行选择(即对于ComposeMessageView不显示)。感谢蒂姆·U 我的最终代码:
<!-- Add reference to the custom DataTemplateSelector namespace -->
xmlns:helpers="clr-namespace:MyCompany.Wpf.Modules.Messaging.Helpers"
<!-- Include the template selector within Resouces (in my case within UserControl.Resources) -->
<helpers:HamburgerMenuIconItemTemplateSelector x:Key="MenuDataTemplateSelector"/>
<!-- This is the template for the menu items (no badge/count control). -->
<DataTemplate x:Key="MenuItemTemplate" DataType="{x:Type Controls:HamburgerMenuIconItem}">
<Grid Height="48">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{Binding Icon}"
Focusable="False"
IsTabStop="False" />
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding Label}" />
</Grid>
</DataTemplate>
<!-- This is the template for the menu items (with badge/count control). -->
<DataTemplate x:Key="MenuItemTemplateBadged" DataType="{x:Type Controls:HamburgerMenuIconItem}">
<Grid Height="48">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Controls:Badged Grid.Column="0"
Badge="{Binding Tag.DataContext.UnreadMessagesCount}"
BadgeBackground="Red"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<ContentControl Content="{Binding Icon}"
Margin="2"
Focusable="False"
IsTabStop="False" />
</Controls:Badged>
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding Label}" />
</Grid>
</DataTemplate>
<Controls:HamburgerMenu x:Name="HamburgerMenuControl"
HamburgerWidth="48"
IsPaneOpen="True"
CanResizeOpenPane="True"
ItemInvoked="HamburgerMenuControl_OnItemInvoked"
ItemTemplateSelector="{StaticResource MenuDataTemplateSelector}"
SelectedIndex="0"
Style="{StaticResource MahApps.Styles.HamburgerMenu.Ripple}"
VerticalScrollBarOnLeftSide="False">
<!-- Items -->
<Controls:HamburgerMenu.ItemsSource>
<Controls:HamburgerMenuItemCollection>
<Controls:HamburgerMenuIconItem Icon="{iconPacks:FontAwesome Kind=CommentAltSolid}" Label="Chat">
<Controls:HamburgerMenuIconItem.Tag>
<views:ChatView />
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
<Controls:HamburgerMenuIconItem Icon="{iconPacks:FontAwesome Kind=PenSquareSolid}" Label="Compose">
<Controls:HamburgerMenuIconItem.Tag>
<views:ComposeMessageView />
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
<Controls:HamburgerMenuIconItem Icon="{iconPacks:Material Kind=InboxArrowDown}" Label="Inbox">
<Controls:HamburgerMenuIconItem.Tag>
<views:InboxView />
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
</Controls:HamburgerMenuItemCollection>
</Controls:HamburgerMenu.ItemsSource>
...
<!-- The custom data template selector class. -->
namespace MyCompany.Wpf.Modules.Messaging.Helpers
{
using System.Windows;
using System.Windows.Controls;
using MyCompany.Wpf.Modules.Messaging.ViewModels;
using MyCompany.Wpf.Modules.Messaging.Views;
using MahApps.Metro.Controls;
public class HamburgerMenuIconItemTemplateSelector: DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
if (element != null && item != null && item is HamburgerMenuIconItem)
{
var count = GetUnreadMessagesCount((HamburgerMenuIconItem)item);
if (count == -1)
{
return element.FindResource("MenuItemTemplate") as DataTemplate;
}
return element.FindResource("MenuItemTemplateBadged") as DataTemplate;
}
return null;
}
private int GetUnreadMessagesCount(HamburgerMenuIconItem item)
{
// Get the view/user control
var viewUserControl = (UserControl)item.Tag;
// Get the data context. NOTE: All view models in the example
// inherit from BaseMessageViewModel that exposes property
// UnreadMessagesCount - and this property is set to -1 when
// the view model is constructed.
var dataContext = (BaseMessageViewModel)viewUserControl.DataContext;
return dataContext.UnreadMessagesCount;
}
}
}
xmlns:helpers=“clr命名空间:MyCompany.Wpf.Modules.Messaging.helpers”
...
命名空间MyCompany.Wpf.Modules.Messaging.Helpers
{
使用System.Windows;
使用System.Windows.Controls;
使用MyCompany.Wpf.Modules.Messaging.ViewModels;
使用MyCompany.Wpf.Modules.Messaging.Views;
使用MahApps.Metro.Controls;
公共类HamburgerManuiconItemTemplateSelector:DataTemplateSelector
{
公共覆盖数据模板SelectTemplate(对象项,DependencyObject容器)
{
FrameworkElement=容器作为FrameworkElement;
如果(元素!=null&&item!=null&&item为HamburgerMenuIconItem)
{
var count=getUnderMessagesCount((HamburgerMenuIconItem)项);
如果(计数==-1)
{
返回元素.FindResource(“MenuItemTemplate”)作为DataTemplate;
}
返回元素.FindResource(“MenuItemTemplateBadged”)作为DataTemplate;
}
返回null;
}
private int getUnderMessagesCount(HamburgerMenuIconItem项)
{
//获取视图/用户控件
var viewUserControl=(UserControl)item.Tag;
//获取数据上下文。注意:示例中的所有视图模型
//从公开属性的BaseMessageViewModel继承
//UnderMessageCount-并且当
//构建了视图模型。
var dataContext=(BaseMessageViewModel)viewUserControl.dataContext;
返回dataContext.UnreadMessagesCount;
}
}
}
另一个相关问题,如果您不介意的话,您可以使用TemplateSelector声明。我在hamburgermenu中有三个视图(选项),不希望显示其中一个视图(即视图:ComposeMessageView)的badge控件。我在网上搜索过,可以看到在代码隐藏中使用选择器的示例,以及在XAML中使用样式/数据触发器的示例。我试图让代码远离代码隐藏(MVVM方法)。您建议的ItemSelector方法是仅使用XAML还是包含一些代码?如果你能提供一个链接,将不胜感激。谢谢。我想你需要一些代码。我也是XAML的粉丝,但这就像用叉子吃饭一样。大多数时候,这是一个很好的选择,但如果你有汤,你最好用勺子:-)。回到toppic:这里有一个关于示例用法的链接:我已经按照链接的建议实现了一个templateselector,一切都很好。再次感谢@Tim。
`<Controls:HamburgerMenu x:Name="HamburgerMenuControl"
HamburgerWidth="48"
IsPaneOpen="True"
CanResizeOpenPane="True"
ItemInvoked="HamburgerMenuControl_OnItemInvoked"
ItemTemplate="{StaticResource MenuItemTemplate}"
OptionsItemTemplate="{StaticResource MenuItemTemplate}"
SelectedIndex="0"
Style="{StaticResource MahApps.Styles.HamburgerMenu.Ripple}"
VerticalScrollBarOnLeftSide="False">
<!-- Items -->
<Controls:HamburgerMenu.ItemsSource>
<Controls:HamburgerMenuItemCollection>
<Controls:HamburgerMenuIconItem Icon="{iconPacks:FontAwesome Kind=CommentAltSolid}" Label="Chat">
<Controls:HamburgerMenuIconItem.Tag>
<views:ChatView />
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
<Controls:HamburgerMenuIconItem Icon="{iconPacks:FontAwesome Kind=PenSquareSolid}" Label="Compose">
<Controls:HamburgerMenuIconItem.Tag>
<views:ComposeMessageView />
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
<Controls:HamburgerMenuIconItem Icon="{iconPacks:Material Kind=InboxArrowDown}" Label="Inbox">
<Controls:HamburgerMenuIconItem.Tag>
<views:InboxView />
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
</Controls:HamburgerMenuItemCollection>
</Controls:HamburgerMenu.ItemsSource>
...`
<!-- Add reference to the custom DataTemplateSelector namespace -->
xmlns:helpers="clr-namespace:MyCompany.Wpf.Modules.Messaging.Helpers"
<!-- Include the template selector within Resouces (in my case within UserControl.Resources) -->
<helpers:HamburgerMenuIconItemTemplateSelector x:Key="MenuDataTemplateSelector"/>
<!-- This is the template for the menu items (no badge/count control). -->
<DataTemplate x:Key="MenuItemTemplate" DataType="{x:Type Controls:HamburgerMenuIconItem}">
<Grid Height="48">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{Binding Icon}"
Focusable="False"
IsTabStop="False" />
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding Label}" />
</Grid>
</DataTemplate>
<!-- This is the template for the menu items (with badge/count control). -->
<DataTemplate x:Key="MenuItemTemplateBadged" DataType="{x:Type Controls:HamburgerMenuIconItem}">
<Grid Height="48">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Controls:Badged Grid.Column="0"
Badge="{Binding Tag.DataContext.UnreadMessagesCount}"
BadgeBackground="Red"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<ContentControl Content="{Binding Icon}"
Margin="2"
Focusable="False"
IsTabStop="False" />
</Controls:Badged>
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding Label}" />
</Grid>
</DataTemplate>
<Controls:HamburgerMenu x:Name="HamburgerMenuControl"
HamburgerWidth="48"
IsPaneOpen="True"
CanResizeOpenPane="True"
ItemInvoked="HamburgerMenuControl_OnItemInvoked"
ItemTemplateSelector="{StaticResource MenuDataTemplateSelector}"
SelectedIndex="0"
Style="{StaticResource MahApps.Styles.HamburgerMenu.Ripple}"
VerticalScrollBarOnLeftSide="False">
<!-- Items -->
<Controls:HamburgerMenu.ItemsSource>
<Controls:HamburgerMenuItemCollection>
<Controls:HamburgerMenuIconItem Icon="{iconPacks:FontAwesome Kind=CommentAltSolid}" Label="Chat">
<Controls:HamburgerMenuIconItem.Tag>
<views:ChatView />
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
<Controls:HamburgerMenuIconItem Icon="{iconPacks:FontAwesome Kind=PenSquareSolid}" Label="Compose">
<Controls:HamburgerMenuIconItem.Tag>
<views:ComposeMessageView />
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
<Controls:HamburgerMenuIconItem Icon="{iconPacks:Material Kind=InboxArrowDown}" Label="Inbox">
<Controls:HamburgerMenuIconItem.Tag>
<views:InboxView />
</Controls:HamburgerMenuIconItem.Tag>
</Controls:HamburgerMenuIconItem>
</Controls:HamburgerMenuItemCollection>
</Controls:HamburgerMenu.ItemsSource>
...
<!-- The custom data template selector class. -->
namespace MyCompany.Wpf.Modules.Messaging.Helpers
{
using System.Windows;
using System.Windows.Controls;
using MyCompany.Wpf.Modules.Messaging.ViewModels;
using MyCompany.Wpf.Modules.Messaging.Views;
using MahApps.Metro.Controls;
public class HamburgerMenuIconItemTemplateSelector: DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
if (element != null && item != null && item is HamburgerMenuIconItem)
{
var count = GetUnreadMessagesCount((HamburgerMenuIconItem)item);
if (count == -1)
{
return element.FindResource("MenuItemTemplate") as DataTemplate;
}
return element.FindResource("MenuItemTemplateBadged") as DataTemplate;
}
return null;
}
private int GetUnreadMessagesCount(HamburgerMenuIconItem item)
{
// Get the view/user control
var viewUserControl = (UserControl)item.Tag;
// Get the data context. NOTE: All view models in the example
// inherit from BaseMessageViewModel that exposes property
// UnreadMessagesCount - and this property is set to -1 when
// the view model is constructed.
var dataContext = (BaseMessageViewModel)viewUserControl.DataContext;
return dataContext.UnreadMessagesCount;
}
}
}