【问题标题】:Treeview IsExpanded not fires upTreeview IsExpanded 不会启动
【发布时间】:2016-01-27 08:21:55
【问题描述】:

我正在尝试向TreeView 添加捕获IsExpanded 事件的能力。这样当某个 Item 展开时,它会在视图模型上引发属性或命令。

这是我的代码:

  <TreeView  Name="ScenariosTreeView" ItemsSource="{Binding Path=Cat, Mode=TwoWay}" Focusable="True" >
     <TreeView.InputBindings>
       <KeyBinding Key="Delete" Command="{Binding DeleteCommand}" CommandParameter="{Binding SelectedValue ,ElementName=ScenariosTreeView}" />
     </TreeView.InputBindings>

     <TreeView.ItemContainerStyle>
       <Style TargetType="{x:Type TreeViewItem}">
         <Setter Property="IsExpanded" Value="{Binding IsExtended, Mode=TwoWay}" />
         <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
       </Style>
     </TreeView.ItemContainerStyle>

     <TreeView.Resources> 
       <HierarchicalDataTemplate DataType="{x:Type sotc:ScenarioCategory}" ItemsSource="{Binding Path=ScenarioList}" >
         <TextBlock  Text="{Binding Path=Name}" Foreground="Black" IsEnabled="True" Focusable="True"/>
       </HierarchicalDataTemplate>

       <DataTemplate DataType="{x:Type sotc:Scenario}" >
         <TextBlock  Text="{Binding Path=Name, Mode=TwoWay}" />
       </DataTemplate>
     </TreeView.Resources> 
  </TreeView>

我在 IsExpanded(和 IsSelected)的视图模型中也有一个属性,当我展开 TreeviewItem 时,这些都没有出现。 有什么想法吗?

谢谢,

【问题讨论】:

  • 你的scenario 对象是你的视图模型?
  • viewmodel和treeview都有一个列表
  • 使用TemplateBinding 而不是Binding
  • 您的 XAML 看起来不错,当您单击树时,应在 ViewModel 中设置 IsExtended 和 IsSelected 属性。您可以查看 Visual Studio 中的输出窗口,可能存在绑定错误,如下所示:“System.Windows.Data 错误:40:BindingExpression 路径错误:在 'object' ''ScenarioCategory' 上找不到 'IsExtended' 属性”
  • 如果需要在树节点展开时触发命令,可以尝试使用附加行为:stackoverflow.com/a/23318067/5574010

标签: c# wpf mvvm treeview


【解决方案1】:

尝试重现该问题并实现了在节点展开且一切正常时调用命令的附加行为。解决方案的完整代码:

XAML

<Window x:Class="TreeViewTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:sotc="clr-namespace:TreeViewTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <sotc:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <TreeView  Name="ScenariosTreeView" ItemsSource="{Binding Path=Cat, Mode=TwoWay}" Focusable="True" >
            <TreeView.InputBindings>
                <KeyBinding Key="Delete" Command="{Binding DeleteCommand}" CommandParameter="{Binding SelectedValue ,ElementName=ScenariosTreeView}" />
            </TreeView.InputBindings>

            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="{Binding IsExtended, Mode=TwoWay}" />
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
                    <Setter Property="sotc:Behaviours.ExpandingBehaviour" Value="{Binding DataContext.ExpandingCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
                </Style>
            </TreeView.ItemContainerStyle>

            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type sotc:ScenarioCategory}" ItemsSource="{Binding Path=ScenarioList}" >
                    <TextBlock  Text="{Binding Path=Name}" Foreground="Black" IsEnabled="True" Focusable="True"/>
                </HierarchicalDataTemplate>

                <DataTemplate DataType="{x:Type sotc:Scenario}" >
                    <TextBlock  Text="{Binding Path=Name, Mode=TwoWay}" />
                </DataTemplate>
            </TreeView.Resources>
        </TreeView>
    </Grid>
</Window>

C#

public class ViewModelBase : INotifyPropertyChanged
{

    public void OnPropertyChanged([CallerMemberName] string name = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

public class MainWindowViewModel : ViewModelBase
{
    public ICommand ExpandingCommand { get; set; }

    private void ExecuteExpandingCommand(object obj)
    {
        Console.WriteLine(@"Expanded");
    }
    private bool CanExecuteExpandingCommand(object obj)
    {
        return true;
    }

    public MainWindowViewModel()
    {
        ExpandingCommand = new RelayCommand(ExecuteExpandingCommand, CanExecuteExpandingCommand);

        Cat = new ObservableCollection<ScenarioCategory>(new ScenarioCategory[] 
        {
            new ScenarioCategory { Name = "C1" }, new ScenarioCategory { Name = "C2" }, new ScenarioCategory { Name = "C3" }
        });
    }

    public ObservableCollection<ScenarioCategory> Cat { get; set; }
}


public class ScenarioCategory : ViewModelBase
{
    string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; OnPropertyChanged(); }
    }

    bool _isExtended;
    public bool IsExtended
    {
        get { return _isExtended; }
        set
        {
            _isExtended = value;
            Console.WriteLine(@"IsExtended set");
            OnPropertyChanged();
        }
    }

    bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            _isSelected = value;
            Console.WriteLine(@"IsSelected set");
            OnPropertyChanged();
        }
    }

    public ObservableCollection<Scenario> ScenarioList { get; set; }

    public ScenarioCategory()
    {
        ScenarioList = new ObservableCollection<Scenario>(new Scenario[] { new Scenario { Name = "1" }, new Scenario { Name = "2" }, new Scenario { Name = "3" } });
    }

}

public class Scenario : ViewModelBase
{
    string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; OnPropertyChanged(); }
    }

    bool _isExtended;
    public bool IsExtended
    {
        get { return _isExtended; }
        set
        {
            _isExtended = value;
            OnPropertyChanged();
        }
    }

    bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            _isSelected = value;
            OnPropertyChanged();
        }
    }
}


public static class Behaviours
{
    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;
                };
            }
        }
    }
}


public class RelayCommand : ICommand
{
    private Action<object> execute;
    private Func<object, bool> canExecute;

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        this.execute = execute;
        this.canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return this.canExecute == null || this.canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        this.execute(parameter);
    }
}

【讨论】:

    【解决方案2】:

    找到了答案。如果它被放置在表示为 treeviewItem 的对象中而不是视图模型中,它会触发该事件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-12
      • 2012-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-23
      相关资源
      最近更新 更多