【问题标题】:Custom Treeview User Control MVVM Double Click Bubbling Event WPF自定义 Treeview 用户控件 MVVM 双击冒泡事件 WPF
【发布时间】:2012-08-09 05:57:53
【问题描述】:

我正在尝试制作自定义 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 项中获取冒泡鼠标双击并在用户控件外部的网格包装器中拦截事件。我试图添加 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>

【问题讨论】:

  • 是否要从外部双击Treeview中的选定项执行命令?
  • 是的,完全一样,有什么想法吗?

标签: c# .net wpf wpf-controls


【解决方案1】:

您根本不需要在用户控件之外发布双击事件。 您需要在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"},
                    }
                },
            }
        };
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-20
    • 2011-02-23
    • 1970-01-01
    • 2020-10-08
    • 1970-01-01
    • 2013-09-20
    相关资源
    最近更新 更多