首页 文章

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

提问于
浏览
2

我正在尝试创建自定义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 回答

  • 2

    您根本不需要在用户控件外部发布双击事件 . 您需要在TreeView.SelectedItemInputBindings集合中添加一些InputBinding(在此特定情况下为MouseBinding) .

    问题是你不能以正常,明显的方式做到这一点 - 通过 TreeView.ItemContainerStyle 设置 InputBindings ,因为 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"},
                        }
                    },
                }
            };
        }
    }
    

相关问题