2012-08-13 142 views
2

我正在尝试使自定义TreeView,并使其成为用户控件。当我将用户控件包装在另一个窗口中时,我尝试在主窗口中获取TreeView项双击事件。自定义TreeView用户控件MVVM双击冒泡事件WPF

<Window xmlns:avalondock="http://avalondock.codeplex.com"  x:Class="WellsVisualizationWPF.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:well="clr-namespace:VisualizationWPF.ViewModel.ViewUserControl" 
    Title="e-IFD" Height="408" Width="558" WindowState="Maximized" 
    > 
<Grid MinWidth="100" **TreeViewItem.MouseLeftButtonClick=<EventHandler>**> <-- Trying to override but failed :p           
    <local:CustomTreeView /> 
</Grid> 

我试图让从CustomTreeView项目冒泡鼠标双击并在用户控件外电网包装截获该事件。我试图添加TreeViewItem。 TreeViewItem.MouseLeftButtonDown =“Grid_MouseLeftButtonDown和失败。任何想法来解决我的问题?

这里是我的树视图自定义用户控件的代码

<UserControl x:Class="WellsVisualizationWPF.ViewModel.ViewUserControl.WellsTreeView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
     xmlns:local="clr-namespace:VisualizationWPF.ViewModel"   
     > 
<Grid MinWidth="100"> 
    <Grid.RowDefinitions> 
     <RowDefinition MaxHeight="500" /> 
     <RowDefinition Height="Auto" /> 
    </Grid.RowDefinitions> 
    <StackPanel Grid.Row="1"> 
     <TextBlock TextWrapping="Wrap" FontSize="12"> 
     Text1 
     </TextBlock> 
     <Button Height="24" Content="Add New" Name="btn_add" Click="btn_add_Click" /> 
    </StackPanel> 
    <ScrollViewer> 
     <DockPanel> 
      <TreeView Grid.Row="0" ItemsSource="{Binding Data}"> 
       <TreeView.Resources> 
        <HierarchicalDataTemplate 
        DataType="{x:Type local:MainViewModel}" 
        ItemsSource="{Binding Children}" 
        > 
         <StackPanel Orientation="Horizontal"> 
          <TextBlock Text="{Binding Name}" /> 
         </StackPanel> 
        </HierarchicalDataTemplate> 
        <DataTemplate DataType="{x:Type local:ParamsViewModel}"> 
         <TextBlock Text="{Binding Name}" />        
        </DataTemplate> 
       </TreeView.Resources>      
      </TreeView> 
     </DockPanel> 
    </ScrollViewer> 
</Grid> 

+0

您是否想从外部双击'Treeview'中的选定项目来执行命令? – Dennis 2012-08-13 06:54:31

+0

是的,完全如此,有什么想法? – euclid135 2012-08-13 12:51:00

+0

添加了答案。 – Dennis 2012-08-13 13:18:30

回答

2

你并不需要发布双单击事件外,从用户控制的。 您需要添加一些InputBindingMouseBinding在这种特殊情况下)为InputBindings收集TreeView.SelectedItem的。

问题是,你不能以正常,明显的方式做到这一点 - 通过TreeView.ItemContainerStyle设置InputBindings,因为InputBindings集合是只读的。伤心,但是真的。

好消息是,您可以使用附加属性来完成该操作。 样本:

查看模型。
一)这是将显示在树视图中的项目:

public class Node : ViewModelBase 
{ 
    public String Text 
    { 
     get { return text; } 
     set 
     { 
      if (text != value) 
      { 
       text = value; 
       OnPropertyChanged("Text"); 
      } 
     } 
    } 
    private String text; 

    public ObservableCollection<Node> Nodes { get; set; } 
} 

b)本是“主”视图模型:

public class ViewModel : ViewModelBase 
{ 
    public ViewModel() 
    { 
     this.selectedNodeDoubleClickedCommand = new RelayCommand<Node>(node => 
     { 
      Debug.WriteLine(String.Format("{0} clicked!", node.Text)); 
     }); 
    } 

    public ObservableCollection<Node> Nodes { get; set; } 

    public RelayCommand<Node> SelectedNodeDoubleClickedCommand 
    { 
     get { return selectedNodeDoubleClickedCommand; } 
    } 
    private readonly RelayCommand<Node> selectedNodeDoubleClickedCommand; 
} 

用户控件的代码隐藏。基本思想 - 我们增加一个附加属性来设置输入XAML虽然结合,而另一个 - 允许外界绑定命令,当输入绑定火灾:

public partial class UserControl1 : UserControl 
{ 
    public UserControl1() 
    { 
     InitializeComponent(); 
    } 

    public ICommand SelectedItemDoubleClickedCommand 
    { 
     get { return (ICommand)GetValue(SelectedItemDoubleClickedCommandProperty); } 
     set { SetValue(SelectedItemDoubleClickedCommandProperty, value); } 
    } 

    public static readonly DependencyProperty SelectedItemDoubleClickedCommandProperty = DependencyProperty.Register(
     "SelectedItemDoubleClickedCommand", typeof(ICommand), 
     typeof(UserControl1), 
     new UIPropertyMetadata(null)); 

    public static ICommand GetSelectedItemDoubleClickedCommandAttached(DependencyObject obj) 
    { 
     return (ICommand)obj.GetValue(SelectedItemDoubleClickedCommandAttachedProperty); 
    } 

    public static void SetSelectedItemDoubleClickedCommandAttached(DependencyObject obj, ICommand value) 
    { 
     obj.SetValue(SelectedItemDoubleClickedCommandAttachedProperty, value); 
    } 

    public static readonly DependencyProperty SelectedItemDoubleClickedCommandAttachedProperty = DependencyProperty.RegisterAttached(
     "SelectedItemDoubleClickedCommandAttached", 
     typeof(ICommand), typeof(UserControl1), 
     new UIPropertyMetadata(null, SelectedItemDoubleClickedCommandAttachedChanged)); 

    private static void SelectedItemDoubleClickedCommandAttachedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var item = d as TreeViewItem; 
     if (item != null) 
     { 
      if (e.NewValue != null) 
      { 
       var binding = new MouseBinding((ICommand)e.NewValue, new MouseGesture(MouseAction.LeftDoubleClick)); 

       BindingOperations.SetBinding(binding, InputBinding.CommandParameterProperty, new Binding("SelectedItem") 
       { 
        RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(TreeView), 1) 
       }); 

       item.InputBindings.Add(binding); 
      } 
     } 
    } 
} 

用户控制XAML:

<Grid> 
    <TreeView ItemsSource="{Binding Nodes}"> 
     <TreeView.Resources> 
      <HierarchicalDataTemplate ItemsSource="{Binding Nodes}" DataType="{x:Type local:Node}"> 
       <TextBlock Text="{Binding Text}"/> 
      </HierarchicalDataTemplate> 
     </TreeView.Resources> 
     <TreeView.ItemContainerStyle> 
      <Style TargetType="{x:Type TreeViewItem}"> 
       <Setter Property="local:UserControl1.SelectedItemDoubleClickedCommandAttached" 
         Value="{Binding SelectedItemDoubleClickedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" /> 
      </Style> 
     </TreeView.ItemContainerStyle> 

    </TreeView> 
</Grid> 

主窗口XAML:

<Window x:Class="WpfApplication2.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:WpfApplication2" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <local:UserControl1 SelectedItemDoubleClickedCommand="{Binding SelectedNodeDoubleClickedCommand}"/> 
    </Grid> 
</Window> 

主窗口代码隐藏:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = new ViewModel 
     { 
      Nodes = new ObservableCollection<Node> 
      { 
       new Node 
       { 
        Text = "Parent 1", 
        Nodes = new ObservableCollection<Node> 
        { 
         new Node { Text = "Child 1.1"}, 
         new Node { Text = "Child 1.2"}, 
        } 
       }, 
       new Node 
       { 
        Text = "Parent 2", 
        Nodes = new ObservableCollection<Node> 
        { 
         new Node { Text = "Child 2.1"}, 
         new Node { Text = "Child 2.2"}, 
        } 
       }, 
      } 
     }; 
    } 
}