自定义控件:ItemContainerStyle

时间:2016-03-31 00:37:46

标签: c# wpf data-binding

我正在使用资源管理器树视图(由我设计的自定义wpf控件)。我在 Generic.xaml:

中有此代码
<Style TargetType="{x:Type local:ExplorerControl}">
    <Setter Property="Template" >
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:ExplorerControl}">
                <Border> 
                        <TreeView Name="myTreeView" >                              
                            <TreeView.ItemContainerStyle>
                                <Style TargetType="{x:Type TreeViewItem}">                                       
                                    <Setter Property="ContextMenu">
                                        <Setter.Value>
                                            <ContextMenu>
                                            <MenuItem x:Name="myTemplate" Header="Remove" Command="{TemplateBinding  RemoveCommand}"></MenuItem>
                                            </ContextMenu>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </TreeView.ItemContainerStyle>
                            <TreeView.ItemTemplate>
                                <HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
                                    <StackPanel Orientation="Horizontal">                                          
                                        <TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
                                    </StackPanel>
                                </HierarchicalDataTemplate>
                            </TreeView.ItemTemplate>
                        </TreeView> 
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

ExplorerControl 中,我有我的依赖属性:

public class ExplorerControl : Control{

    public ExplorerControl()
    {
        Nodes = new ObservableCollection<Node>();
    } 

    private ObservableCollection<Node> Nodes { get; }

    public ICommand RemoveCommand
    {
        get { return (ICommand)GetValue(RemovedCommandProperty); }
        set { SetValue(RemovedCommandProperty, value); }
    }

        public static readonly DependencyProperty RemovedCommandProperty =
            DependencyProperty.Register("RemoveCommand", typeof(ICommand), typeof(ExplorerControl));
}

节点类

public class Node {
    public string Name {get;set;}
}

我的问题是我不知道如何让MenuItem Command工作

我试过这些:

  1. 如果我在TreeView之后使用相同的代码和一个按钮(两个都在Stackpanel中),它可以工作。所以我认为问题是MenuItem DataContext
  2. 我尝试更改MenuItem DataContext但是我没有得到它。
  3. 我希望你能帮助我。

    编辑:我删除了有关DataContext的部分代码。谢谢你的答案。

    我在MainView中使用此控件:

       <treeViewExplorerControl:ExplorerControl                                    
       SelectedItemName="{Binding SelectedItemName}"
       SelectedItemPath="{Binding SelectedItemPath}"                                
       RemoveCommand="{Binding ExplorerControlItemRemovedCommand}"/>
    

2 个答案:

答案 0 :(得分:1)

提议的解决方案:

MenuItem Commands尝试使用祖先绑定。

<MenuItem x:Name="myTemplate" Header="Remove"
          Command="{Binding RelativeSource={RelativeSource Path=RemoveCommand, AncestorType={x:Type ExplorerControl}, Mode=FindAncestor" />

我相信您DataContext正在发生变化的原因是因为您指向Nodes并在Node中显示每个MenuItem。但是,Node不包含您尝试绑定的命令。

<TreeView.ItemTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
        <StackPanel Orientation="Horizontal">                                          
            <TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
        </StackPanel>
    </HierarchicalDataTemplate>
</TreeView.ItemTemplate>

如果您不确定DataContext,可以使用Snoop查看当前的DataContext。

额外信息:

我认为您不需要指出DataContext的{​​{1}}。它会自动传递下去。

TreeView

您不必将<TreeView.DataContext> <local:ExplorerControl x:Name="explorer" /> </TreeView.DataContext> DependencyProperty一起使用。在ICommand的构造函数中,您可以将ExplorerControl实例化为ICommand

  1. 创建一个继承自DelegateCommand的{​​{1}}类。这将是DelegateCommand的具体实现。你可以在这里找到:http://www.wpftutorial.net/delegatecommand.html
  2. 使用ICommand实例化您的ICommand,并将您的方法(位于ICommands)传递给构造函数。
  3. 例如:

    DelegateCommand

答案 1 :(得分:1)

最后我找到了解决方案。

首先,我发现了关于ContextMenu:

  

因为WPF中的ContextMenu在页面/窗口/控件本身的可视树中不存在,所以数据绑定可能有点棘手。

Source

通过这个例子,我编写了这段代码,并且我认为它运行良好:

<Style TargetType="{x:Type local:ExplorerControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ExplorerControl}">
                    <Border>
                        <TreeView Name="myTreeView">
                            <TreeView.Resources>
                                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#FF003BB0" />
                            </TreeView.Resources>
                            <TreeView.ItemContainerStyle>
                                <Style TargetType="{x:Type TreeViewItem}">
                                    <Setter Property="IsExpanded" Value="True" />
                                </Style>
                            </TreeView.ItemContainerStyle>
                            <TreeView.ItemTemplate>
                                <HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
                                    <StackPanel Orientation="Horizontal"
                                                Tag="{Binding TemplatedParent,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeView}}}">                                      
                                        <TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
                                        <StackPanel.ContextMenu>
                                            <ContextMenu>
                                                <MenuItem x:Name="myTemplate"
                                                          Header="Remove"
                                                          DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"
                                                          Command="{Binding Path=Tag.RemoveCommand}"
                                                          CommandParameter="{Binding Path=DataContext}">                                    
                                                </MenuItem>
                                            </ContextMenu>
                                        </StackPanel.ContextMenu>
                                    </StackPanel>
                                </HierarchicalDataTemplate>
                            </TreeView.ItemTemplate>
                        </TreeView>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

我保存在Stackpanel标签中,我的explorerControl的引用,然后我使用PlacementTarget来获取Stackpanel参考

我希望此代码可以帮助其他人。