WPF TreeView在ControlTemplate中 - 处理项目扩展

发布于 2025-01-26 08:42:37 字数 1610 浏览 3 评论 0原文

我正在创建一个自定义控件,在控制模板中,我中有一个TreeView类。

<Style TargetType="{x:Type local:MyControl}">

<Setter Property="Template">

    <Setter.Value>

        <ControlTemplate TargetType="{x:Type local:MyControl}">

            <Border>

                <TreeView ItemsSource="{Binding TreeDataItems, RelativeSource={RelativeSource TemplatedParent}}">

                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="TreeViewItem.Expanded">
                            <i:InvokeCommandAction Command="{Binding TreeItemExpandedCommand, RelativeSource={RelativeSource TemplatedParent}}"
                                                CommandParameter="{Binding}">

                            </i:InvokeCommandAction>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>

                </TreeView>
            </Border>

        </ControlTemplate>

    </Setter.Value>

</Setter>

在自定义控件的代码文件中,我有此命令:

private ICommand _TreeItemExpandedCommand;

public icommand treeTempandedCommand { 得到 { if(_treeItemExpandedCommand == null) _treeItemExpandEdCommand = new RelayCommand(p =&gt; treeItemExpandExeceCected(p)); 返回_treeItemExpandedCommand; } }

私有void treeTemExpandEdexecected(对象args) { }

我还尝试了

<TreeView TreeViewItem.Expanded="TreeViewItem_Expanded">
...

&lt;/treeview/&gt;

但是都没有被解雇。

如何在自定义控件的代码文件中处理TreeView的扩展事件?

谢谢

I am creating a Custom Control and in the control template I have a TreeView class in it.

<Style TargetType="{x:Type local:MyControl}">

<Setter Property="Template">

    <Setter.Value>

        <ControlTemplate TargetType="{x:Type local:MyControl}">

            <Border>

                <TreeView ItemsSource="{Binding TreeDataItems, RelativeSource={RelativeSource TemplatedParent}}">

                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="TreeViewItem.Expanded">
                            <i:InvokeCommandAction Command="{Binding TreeItemExpandedCommand, RelativeSource={RelativeSource TemplatedParent}}"
                                                CommandParameter="{Binding}">

                            </i:InvokeCommandAction>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>

                </TreeView>
            </Border>

        </ControlTemplate>

    </Setter.Value>

</Setter>

In the code file for the custom control I have this command:

private ICommand _TreeItemExpandedCommand;

public ICommand TreeItemExpandedCommand
{
get
{
if (_TreeItemExpandedCommand == null)
_TreeItemExpandedCommand = new RelayCommand(p => TreeItemExpandedExecuted(p));
return _TreeItemExpandedCommand;
}
}

private void TreeItemExpandedExecuted(object args)
{
}

I have also tried

<TreeView TreeViewItem.Expanded="TreeViewItem_Expanded">
...

</TreeView/>

but neither gets fired.

How can I handle the TreeView's Expanded event INSIDE my custom control's code file?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

呆橘 2025-02-02 08:42:37

我不是Pro WPF程序员,但我设法找出解决方案的问题。代码的问题在于,该事件并不完全属于TreeView本身,而是其中的元素(项目属性)。

因此,这种工作无法做到:

...
<i:EventTrigger EventName="TreeViewItem.Expanded">
...

另一方面,这将有效:

...
<i:EventTrigger EventName="SelectedItemChanged">
...

因为此事件基本上属于Treeview

,所以您需要做的是订阅TreeView中所有TreeViewItems的扩展事件。您可以从后面的代码中执行此操作。

这是我的做法:

public class MyCustomControl : Control
{
    public TreeView MyTreeView { get; set; }

    public static readonly DependencyProperty TreeViewItemListProperty = DependencyProperty.Register("TreeViewItemList", 
                                                                                              typeof(List<StorageItem>), 
                                                                                              typeof(MyCustomControl), 
                                                                                              new UIPropertyMetadata(null));

    public List<StorageItem> TreeViewItemList
    {
        get { return (List<StorageItem>)GetValue(TreeViewItemListProperty); }
        set { SetValue(TreeViewItemListProperty, value);}
    }

    public static readonly RoutedEvent MyEventRoutedEvent = EventManager.RegisterRoutedEvent("MyEvent", 
                                                                                              RoutingStrategy.Bubble, 
                                                                                              typeof(EventHandler<RoutedEventArgs>), 
                                                                                              typeof(MyCustomControl));
    public event RoutedEventHandler MyEvent
    {
        add { this.AddHandler(MyEventRoutedEvent, value); }
        remove { this.RemoveHandler(MyEventRoutedEvent, value); }
    }


    public override void OnApplyTemplate()
    {
        MyTreeView = Template.FindName("MyTreeView", this) as TreeView;
        MyTreeView.Items.CurrentChanged += Items_CurrentChanged;
        base.OnApplyTemplate();
    }

    private void Items_CurrentChanged(object sender, EventArgs e)
    {
        SubscribeAllTreeViewItems(MyTreeView);
    }

    private void SubscribeAllTreeViewItems(ItemsControl treeViewItem)
    {
        foreach (object item in treeViewItem.Items)
        {
            TreeViewItem treeItem = treeViewItem.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
            if (treeItem != null)
            {
                SubscribeAllTreeViewItems(treeItem);
                treeItem.Expanded += TreeViewItem_Expanded;
            }
        }
    }

    private void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
    {
        RoutedEventArgs args = new RoutedEventArgs(MyEventRoutedEvent, this);
        this.RaiseEvent(args);
    }

    static MyCustomControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl)));
    }
}

首先,我们需要获取树景的控制并在事件中订阅项目:

    public override void OnApplyTemplate()
    {
        MyTreeView = Template.FindName("MyTreeView", this) as TreeView;
        MyTreeView.Items.CurrentChanged += Items_CurrentChanged;
        base.OnApplyTemplate();
    }

然后,如果要发射此事,我们知道我们的TreeView中有项目,因此我们可以循环浏览其元素并订阅为了扩展活动:

private void Items_CurrentChanged(object sender, EventArgs e)
    {
        SubscribeAllTreeViewItems(MyTreeView);
    }

    private void SubscribeAllTreeViewItems(ItemsControl treeViewItem)
    {
        foreach (object item in treeViewItem.Items)
        {
            TreeViewItem treeItem = treeViewItem.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
            if (treeItem != null)
            {
                SubscribeAllTreeViewItems(treeItem);
                treeItem.Expanded += TreeViewItem_Expanded;
            }
        }
    }

之后,我们很高兴!我还添加了代码,以便能够从自定义控件外部订阅此事件:

    public static readonly RoutedEvent MyEventRoutedEvent = EventManager.RegisterRoutedEvent("MyEvent", 
                                                                                              RoutingStrategy.Bubble, 
                                                                                              typeof(EventHandler<RoutedEventArgs>), 
                                                                                              typeof(MyCustomControl));
    public event RoutedEventHandler MyEvent
    {
        add { this.AddHandler(MyEventRoutedEvent, value); }
        remove { this.RemoveHandler(MyEventRoutedEvent, value); }
    }
    ....
    ....
    private void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
    {
        RoutedEventArgs args = new RoutedEventArgs(MyEventRoutedEvent, this);
        this.RaiseEvent(args);
    }

因此,这样,您可以从外部订阅它:

  <local:MyCustomControl TreeViewItemList="{Binding Path=Items}"
                         MyEvent="MyCustomControl_MyEvent"/>

最后,这是.xaml

<Style TargetType="{x:Type local:MyCustomControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:MyCustomControl}">
                <TreeView ItemsSource="{TemplateBinding TreeViewItemList}"
                              x:Name="MyTreeView">
                    <TreeView.Resources>
                        <!--Here we specify how to display a FolderItem-->
                        <HierarchicalDataTemplate DataType="{x:Type localviewmodels:FolderItem}"
                                                  ItemsSource="{Binding Path=Items}">
                            <TextBlock Text="{Binding Path=Name}"
                                       Margin="0 0 35 0"/>
                        </HierarchicalDataTemplate>

                        <!--Here we specify how to display a FileItem-->
                        <DataTemplate DataType="{x:Type localviewmodels:FileItem}">

                            <TextBlock Text="{Binding Path=Name}"
                                           Margin="0 0 35 0"/>
                        </DataTemplate>
                    </TreeView.Resources>
                </TreeView>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Update

如果您想要在自定义控件中设置树视图项目,您应该
订阅MyTreeView.loaded事件,以捕获其获得值时的第一次。

我希望它有帮助!
如果有什么不清楚的话,请随时提出,我准备帮助!

I am not pro Wpf programmer, but i manage to figure out the solution for your problem. The problem with your code, is that the event is not exactly belongs to TreeView itself, but rather the elements inside it (Items property).

So this wont work:

...
<i:EventTrigger EventName="TreeViewItem.Expanded">
...

On the other hand, this would work:

...
<i:EventTrigger EventName="SelectedItemChanged">
...

because this event belongs to TreeView

Basicly, what you need to do is subscribe for the Expanded event of all the TreeViewItems in the TreeView. You can do this from code behind.

Here is how i did it:

public class MyCustomControl : Control
{
    public TreeView MyTreeView { get; set; }

    public static readonly DependencyProperty TreeViewItemListProperty = DependencyProperty.Register("TreeViewItemList", 
                                                                                              typeof(List<StorageItem>), 
                                                                                              typeof(MyCustomControl), 
                                                                                              new UIPropertyMetadata(null));

    public List<StorageItem> TreeViewItemList
    {
        get { return (List<StorageItem>)GetValue(TreeViewItemListProperty); }
        set { SetValue(TreeViewItemListProperty, value);}
    }

    public static readonly RoutedEvent MyEventRoutedEvent = EventManager.RegisterRoutedEvent("MyEvent", 
                                                                                              RoutingStrategy.Bubble, 
                                                                                              typeof(EventHandler<RoutedEventArgs>), 
                                                                                              typeof(MyCustomControl));
    public event RoutedEventHandler MyEvent
    {
        add { this.AddHandler(MyEventRoutedEvent, value); }
        remove { this.RemoveHandler(MyEventRoutedEvent, value); }
    }


    public override void OnApplyTemplate()
    {
        MyTreeView = Template.FindName("MyTreeView", this) as TreeView;
        MyTreeView.Items.CurrentChanged += Items_CurrentChanged;
        base.OnApplyTemplate();
    }

    private void Items_CurrentChanged(object sender, EventArgs e)
    {
        SubscribeAllTreeViewItems(MyTreeView);
    }

    private void SubscribeAllTreeViewItems(ItemsControl treeViewItem)
    {
        foreach (object item in treeViewItem.Items)
        {
            TreeViewItem treeItem = treeViewItem.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
            if (treeItem != null)
            {
                SubscribeAllTreeViewItems(treeItem);
                treeItem.Expanded += TreeViewItem_Expanded;
            }
        }
    }

    private void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
    {
        RoutedEventArgs args = new RoutedEventArgs(MyEventRoutedEvent, this);
        this.RaiseEvent(args);
    }

    static MyCustomControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl)));
    }
}

First we need to acquire our TreeView Control and subscribe the event if it gets items:

    public override void OnApplyTemplate()
    {
        MyTreeView = Template.FindName("MyTreeView", this) as TreeView;
        MyTreeView.Items.CurrentChanged += Items_CurrentChanged;
        base.OnApplyTemplate();
    }

Then, if this is fired, we know that our TreeView has Items in it, so we can cycle through its elements and subscribe for the event Expanded:

private void Items_CurrentChanged(object sender, EventArgs e)
    {
        SubscribeAllTreeViewItems(MyTreeView);
    }

    private void SubscribeAllTreeViewItems(ItemsControl treeViewItem)
    {
        foreach (object item in treeViewItem.Items)
        {
            TreeViewItem treeItem = treeViewItem.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
            if (treeItem != null)
            {
                SubscribeAllTreeViewItems(treeItem);
                treeItem.Expanded += TreeViewItem_Expanded;
            }
        }
    }

After that, we are good to go! I also added code for to be able to subscribe for this event from outside the custom control:

    public static readonly RoutedEvent MyEventRoutedEvent = EventManager.RegisterRoutedEvent("MyEvent", 
                                                                                              RoutingStrategy.Bubble, 
                                                                                              typeof(EventHandler<RoutedEventArgs>), 
                                                                                              typeof(MyCustomControl));
    public event RoutedEventHandler MyEvent
    {
        add { this.AddHandler(MyEventRoutedEvent, value); }
        remove { this.RemoveHandler(MyEventRoutedEvent, value); }
    }
    ....
    ....
    private void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
    {
        RoutedEventArgs args = new RoutedEventArgs(MyEventRoutedEvent, this);
        this.RaiseEvent(args);
    }

So this way, you can subscribe it from outside like that:

  <local:MyCustomControl TreeViewItemList="{Binding Path=Items}"
                         MyEvent="MyCustomControl_MyEvent"/>

Finally, here it is the .xaml

<Style TargetType="{x:Type local:MyCustomControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:MyCustomControl}">
                <TreeView ItemsSource="{TemplateBinding TreeViewItemList}"
                              x:Name="MyTreeView">
                    <TreeView.Resources>
                        <!--Here we specify how to display a FolderItem-->
                        <HierarchicalDataTemplate DataType="{x:Type localviewmodels:FolderItem}"
                                                  ItemsSource="{Binding Path=Items}">
                            <TextBlock Text="{Binding Path=Name}"
                                       Margin="0 0 35 0"/>
                        </HierarchicalDataTemplate>

                        <!--Here we specify how to display a FileItem-->
                        <DataTemplate DataType="{x:Type localviewmodels:FileItem}">

                            <TextBlock Text="{Binding Path=Name}"
                                           Margin="0 0 35 0"/>
                        </DataTemplate>
                    </TreeView.Resources>
                </TreeView>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

UPDATE

if you want to set TreeView items inside the custom Control, you should
subscribe the MyTreeView.Loaded event as well to catch the first time when it gets values.

i hope it helps!
If anything is not clear, feel free to ask, i am ready to help!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文