【问题标题】:Custom control: binding in ItemContainerStyle自定义控件:ItemContainerStyle 中的绑定
【发布时间】:2016-07-19 05:55:55
【问题描述】:

我正在使用 Explorer 树视图(我设计的自定义 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 命令起作用

我试过这些:

  1. 如果我在 TreeView 之后使用带有按钮的相同代码(两者都在 Stackpanel 中),它可以工作。所以我认为问题在于 MenuItem DataContext
  2. 我尝试更改 MenuItem DataContext 但没有成功。

我希望你能帮助我。

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

我在我的 MainView 中使用这个控件:

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

【问题讨论】:

  • 请注意,将 ExplorerControl 设置为 TreeView.DataContext 会创建一个新的 ExplorerControl 实例。这没有任何意义。
  • @Clemens 谢谢我对自定义控件有点陌生。我删除了那部分代码。
  • 是窗口中的最后一段代码吗?我不知道您的解决方案如何复制它。
  • @AzzamAziz 我有两个项目,一个是名为 treeViewExplorerControl 的自定义控件,另一个是 WPF 项目,在我的 MainView.xaml 中使用的 WPF 项目中的 ExplorerControl 和最后一段代码。

标签: c# wpf data-binding


【解决方案1】:

建议的解决方案:

在您的MenuItem Commands 中尝试使用祖先绑定。

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

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

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

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

额外信息:

我认为您不需要将DataContext 指向您的TreeView。它是自动传递的。

<TreeView.DataContext>
    <local:ExplorerControl x:Name="explorer" />
</TreeView.DataContext>

您不必将DependencyPropertyICommand 一起使用。在ExplorerControl 的构造函数中,您可以将ICommand 实例化为DelegateCommand

  1. 创建一个继承自ICommandDelegateCommand 类。这将是您对ICommand 的具体实现。你可以在这里找到:http://www.wpftutorial.net/delegatecommand.html
  2. DelegateCommand 实例化您的ICommands,并将您在ExplorerControl 上的方法传递给构造函数。

例如:

public class ExplorerControl : UserControl
{
    public DelegateCommand RemoveCommand { get; set; }

    public ExplorerControl()
    {
        RemoveCommand = new DelegateCommand(Remove);
    }

    private void Remove()
    {
        // Do something here.
    }
}

【讨论】:

  • 感谢您的回答,但我尝试{Binding RelativeSource={RelativeSource AncestorType={x:Type local:ExplorerControl}, Mode=FindAncestor},Path=RemoveCommand} 没有结果。我不能使用你的第二种方法,因为我需要在我的资源管理器控件所在的 MainWindowViewModel 中创建来处理命令。
  • 您能否添加更多代码,以便我可以复制您的代码并查看 DataContext 是什么?
  • 我只是添加它,dataContext是一个节点,因为如果我将命令放在节点中它可以工作。
  • 感谢您的工作,snoop 工具对我的调试帮助很大。
【解决方案2】:

终于找到了解决办法。

首先我发现了关于 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 引用

我希望这段代码将来可以帮助其他人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-03
    • 2011-03-27
    • 1970-01-01
    • 1970-01-01
    • 2013-03-15
    • 2015-02-15
    相关资源
    最近更新 更多