自定义Treeview用户控件MVVM双击冒泡事件WPF

时间:2012-08-13 00:29:32

标签: c# .net wpf wpf-controls

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

<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项目中双击冒泡鼠标,并拦截usercontrol外部网格包装器中的事件。我试图添加TreeViewItem。 TreeViewItem.MouseLeftButtonDown =“Grid_MouseLeftButtonDown并失败。有什么想法可以解决我的问题吗?

这是我的treeview自定义用户控件代码

<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>

1 个答案:

答案 0 :(得分:2)

您根本无需在用户控件外部发布双击事件。 您需要在InputBindingMouseBinding集合中添加一些InputBindings(在此特定情况下为TreeView.SelectedItem)。

问题在于,您无法以正常,明显的方式执行此操作 - 通过InputBindings设置TreeView.ItemContainerStyle,因为InputBindings集合是只读的。悲伤,但却是真的。

好消息是你可以使用附属财产来实现这一目标。 样本:

查看模型。
a)这将在树视图中显示为项目:

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"},
                    }
                },
            }
        };
    }
}