我有一个简单的TreeView
,我正在尝试为其创建自定义DataTemplate
。它会根据需要显示,但是当我尝试选择TreeViewItem
时,如果单击TreeView
中的文本,则突出显示不起作用。但是,如果我选择文本的左侧,它可以工作:
消息来源很简单,所以我猜测我只是缺少样式连接:
XAML
<TreeView x:Name="treeView"
ItemsSource="{Binding TreeViewItems}"
Grid.Row="0">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=MenuItems}">
<TreeViewItem Header="{Binding Header}">
<TreeViewItem.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding Command}" />
</TreeViewItem.InputBindings>
</TreeViewItem>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
我已尝试将其添加到xaml中,但它没有帮助:
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}"
BasedOn="{StaticResource {x:Type TreeViewItem}}" />
</TreeView.ItemContainerStyle>
TreeViewModel
public class TreeViewModel : BaseNotifyModel, ITreeViewModel
{
public TreeViewModel(ITreeViewService menuService)
{
TreeViewItems =
new ReadOnlyObservableCollection<MenuItemViewModel>(menuService.TreeViewMenu);
}
public ReadOnlyObservableCollection<MenuItemViewModel> TreeViewItems
{
get
{
return Get<ReadOnlyObservableCollection<MenuItemViewModel>>();
}
private set
{
Set(value);
}
}
}
MenuItemViewModel
public class MenuItemViewModel : BaseNotifyModel
{
public MenuItemViewModel()
{
MenuItems =
new ObservableCollection<MenuItemViewModel>();
}
public String Header
{
get
{
return Get<String>();
}
set
{
Set(value);
}
}
public ICommand Command
{
get
{
return Get<ICommand>();
}
set
{
Set(value);
}
}
public ObservableCollection<MenuItemViewModel> MenuItems
{
get
{
return Get<ObservableCollection<MenuItemViewModel>>();
}
set
{
Set(value);
}
}
}
答案 0 :(得分:1)
TreeView
为TreeViewItem
中的每个项目创建了ItemsSource
,因此请勿在{{1}}内嵌入另一个TreeViewItem
TreeView
已经为你创造了。这并不是出于任何目的。您的模板应该只是为现有的TreeViewItem
提供一种方式来显示其DataContext
(您的MenuItemViewModel
,在这种情况下)中的任何内容。
您想在树视图项中显示Header
属性;所以就这样做吧。没有什么特别的,只有Label
或ContentControl
,甚至只有TextBlock
String
(虽然它在WPF中很有乐趣任意内容的灵活性)。当用户单击内容时,您的命令将执行。用户可以在树中看到的唯一内容是内容。这是TreeViewItem
项目中唯一可见的部分,因此用户将点击该内容。
问题二:输入绑定获得LeftClick
后,会导致TreeView
中的选择中断。在我看来,你无法通过这种方法从这里到达那里。
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=MenuItems}">
<ContentControl
Content="{Binding Header}"
Background="Transparent"
>
<ContentControl.InputBindings>
<!-- This invokes the command, but breaks selection -->
<MouseBinding MouseAction="LeftClick"
Command="{Binding Command}" />
</ContentControl.InputBindings>
</ContentControl>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
以下是您可以做的事情:
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=MenuItems}">
<ContentControl
Content="{Binding Header}"
Background="Transparent"
>
</ContentControl>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<EventSetter Event="Selected" Handler="MenuTreeViewItem_Click" />
</Style>
</TreeView.ItemContainerStyle>
代码隐藏
private void MenuTreeViewItem_Click(object sender, RoutedEventArgs e)
{
((MenuItemViewModel)((FrameworkElement)sender).DataContext).Command.Execute(null);
}
There is a way to bind an event to a command in pure XAML,但它需要一些C#代码(LOL)。但我的意思是,它是纯粹的XAML&#34;从某种意义上说,它是一个很好的通用可重用附加行为,而不是代码隐藏中的难看的事件处理程序。相反,它完全与我上面所做的完全相同,但它在代码中完成,您可以更轻松地避开您的眼睛,并且您可以在纯XAML中重用它。
答案 1 :(得分:0)
在@Ed Plunket和@Evk的帮助下,我找到了一个可行的解决方案。我切换到ContentPresenter
并使用Interaction.Triggers
在MouseLeftButtonUp
操作上调用命令。
<TreeView ItemsSource="{Binding TreeViewItems}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=MenuItems}">
<ContentPresenter Content="{Binding Header}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction Command="{Binding Path=DataContext.Command, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ContentPresenter>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>