调用命令时,树型视图展开的 [英] Invoke Command when TreeViewItem is Expanded

查看:270
本文介绍了调用命令时,树型视图展开的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

听起来很简单?我有一个TreeView,我想,当一个节点扩展到发生什么。我使用MVVM,让'东西'是在视图模型的命令。

Sounds simple enough? I have a TreeView, and I want something to happen when one of the nodes is expanded. I'm using MVVM, so that 'something' is a command in the ViewModel.

好吧,我发现,它不是那么简单毕竟。我环顾四周,并试图几件事。例如,使用MVVM光的EventToCommand:

Well, I'm finding that it's not so simple after all. I've looked around and tried a few things. For example, using MVVM Light's EventToCommand:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="TreeViewItem.Expanded">
        <cmd:EventToCommand Command="{Binding Path=FolderNodeToggledCommand}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

这代码(基于的这个)不工作(没有火灾;命令为绑定在视图模型,但相应的方法,当一个节点展开从不解雇)。我也试着将 CMD:EventToCommand 我:InvokeCommandAction ,结果是一样的。在第二环节的解决方案显然是矫枉过正,我不希望改变,因为切换按钮我想使用的有其自身的切换按钮WPF的TreeView的WinForms风格。在第二环节的二次答案表明,我可能会尝试在不存在的TreeView使用事件

This code (based on this and this) doesn't work (nothing fires; the command is bound in the ViewModel but the corresponding method is never fired when a node is expanded). I've also tried replacing cmd:EventToCommand with i:InvokeCommandAction and the results are the same. The 'solution' in the second link is clearly overkill and I don't want to change the ToggleButton since I want to use the WPF TreeView WinForms Style which has its own ToggleButton. The secondary answer in the second link suggests that I might be attempting to use an event on TreeView that doesn't exist.

另外的possible解决方案可以绑定TreeViewItem的 IsExpanded 属性。不过,我想保持我结合清洁 的DTO的对象,并在视图模型执行的操作,不在对象的限制。

Another possible solution could be to bind the TreeViewItem's IsExpanded property. However I'd like to keep the objects I'm binding to as clean DTOs and perform an action in the ViewModel, not in the objects being bound.

那么怎么做才能在视图模型来调用命令时,树型视图扩展?

So what will it take to invoke a command in the ViewModel when a TreeViewItem is expanded?

推荐答案

要得到这个工作,你可以使用一个附加的行为,你会看到,这是一个干净的MVVM策略。

To get this working, you can use an attached behaviour, and you'll see that it's a clean MVVM strategy.

创建一个WPF应用程序,并添加此XAML ...

Create a WPF app and add this Xaml...

<Grid>
    <TreeView>
        <TreeView.Resources>
            <Style TargetType="TreeViewItem">
                <Setter Property="bindTreeViewExpand:Behaviours.ExpandingBehaviour" Value="{Binding ExpandingCommand}"/>
            </Style>
        </TreeView.Resources>
        <TreeViewItem Header="this" >
            <TreeViewItem Header="1"/>
            <TreeViewItem Header="2"><TreeViewItem Header="Nested"></TreeViewItem></TreeViewItem>
            <TreeViewItem Header="2"/>
            <TreeViewItem Header="2"/>
            <TreeViewItem Header="2"/>
        </TreeViewItem>
        <TreeViewItem Header="that" >
            <TreeViewItem Header="1"/>
            <TreeViewItem Header="2"/>
            <TreeViewItem Header="2"/>
            <TreeViewItem Header="2"/>
            <TreeViewItem Header="2"/>
        </TreeViewItem>        
    </TreeView>
</Grid>



然后创建一个这样的视图模型......

Then create a View Model like this...

public class ViewModel : INotifyPropertyChanged
{
    public ICommand ExpandingCommand { get; set; }
    public ViewModel()
    {
        ExpandingCommand = new RelayCommand(ExecuteExpandingCommand, CanExecuteExpandingCommand);
    }
    private void ExecuteExpandingCommand(object obj)
    {
        Console.WriteLine(@"Expanded");
    }
    private bool CanExecuteExpandingCommand(object obj)
    {
        return true;
    }
    #region INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string name)
    {
        var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
    #endregion
}



我用的继电器命令,但你可以互换使用Delegate命令。继电器命令的来源是在 http://msdn.microsoft.com/en-us/magazine/ dd419663.aspx

然后创建一个单独的类,看起来像这样...

Then create a separate class that looks like this...

public static class Behaviours
{
    #region ExpandingBehaviour (Attached DependencyProperty)
    public static readonly DependencyProperty ExpandingBehaviourProperty =
        DependencyProperty.RegisterAttached("ExpandingBehaviour", typeof(ICommand), typeof(Behaviours),
            new PropertyMetadata(OnExpandingBehaviourChanged));
    public static void SetExpandingBehaviour(DependencyObject o, ICommand value)
    {
        o.SetValue(ExpandingBehaviourProperty, value);
    }
    public static ICommand GetExpandingBehaviour(DependencyObject o)
    {
        return (ICommand) o.GetValue(ExpandingBehaviourProperty);
    }
    private static void OnExpandingBehaviourChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        TreeViewItem tvi = d as TreeViewItem;
        if (tvi != null)
        {
            ICommand ic = e.NewValue as ICommand;
            if (ic != null)
            {
                tvi.Expanded += (s, a) => 
                {
                    if (ic.CanExecute(a))
                    {
                        ic.Execute(a);

                    }
                    a.Handled = true;
                };
            }
        }
    }
    #endregion
}

然后导入这个类的名称空间分成XAML中...

Then import the name space of this class into your Xaml...

的xmlns:bindTreeViewExpand =CLR的命名空间:BindTreeViewExpand(你的名字空间将不同!)

xmlns:bindTreeViewExpand="clr-namespace:BindTreeViewExpand" (your name space will be different!)

ReSharper的会为你做这个,还是给你一个intellesense提示。

Resharper will do this for you, or give you an intellesense prompt.

最后线建立视图模型。使用快速和肮脏的方法是这样...

Finally wire up the View Model. Use the quick and dirty method like this...

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }



,之后的名称空间解决,接线是否正确,然后它会开始工作。锚调试器在Execute方法,观察你得到一个RoutedEvent的说法。您可以分析这个要获取的树视图项进一步扩大。

Then, after the name spaces are resolved and the wiring is correct, it will start to work. Anchor your debugger in the Execute method and observe that you get a RoutedEvent argument. You can parse this to get which Tree view item was expanded.

在此解决方案的关键方面是在风格被指定的行为!所以它被施加到每一位的TreeViewItem。背后没有任何代码(除行为)。

The key aspect in this solution is the behaviour being specified in the STYLE! So it is applied to each and every TreeViewItem. No code behind either (other than the behaviour).

我上面列出的行为进行处理,标志着该事件。你可能希望改变取决于行为你是后。

The behaviour I listed above marks the event as handled. You may wish to change that depending upon the behaviour you are after.

这篇关于调用命令时,树型视图展开的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆