代码之家  ›  专栏  ›  技术社区  ›  imekon

WPF TreeView MouseDown酒店

  •  2
  • imekon  · 技术社区  · 16 年前

    <DataTemplate x:Key="myTemplate">
        <StackPanel MouseDown="OnItemMouseDown">
        ...
        </StackPanel>
    </DataTemplate>
    

    使用此选项,如果单击堆栈面板中的项,将获得鼠标向下的事件。然而。。。堆栈面板后面似乎还有一个项目是TreeViewItem——很难命中,但并非不可能,问题就在这时开始出现。

    我在TreeViewItem上尝试处理PreviewMouseDown,但是这似乎需要

    e.Handled = false
    

    否则,标准树视图行为将停止工作。


    好的,这是源代码。。。

    主窗口.xaml

    <Window x:Class="WPFMultiSelectTree.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFMultiSelectTree"    
        Title="Multiple Selection Tree" Height="300" Width="300">
    
    <Window.Resources>
    
        <!-- Declare the classes that convert bool to Visibility -->
        <local:VisibilityConverter x:Key="visibilityConverter"/>
        <local:VisibilityInverter x:Key="visibilityInverter"/>
    
        <!-- Set the style for any tree view item -->
        <Style TargetType="TreeViewItem">
    
            <Style.Triggers>
                <DataTrigger Binding="{Binding Selected}" Value="True">
                    <Setter Property="Background" Value="DarkBlue"/>
                    <Setter Property="Foreground" Value="White"/>
                </DataTrigger>
            </Style.Triggers>
    
            <EventSetter Event="PreviewMouseDown" Handler="OnTreePreviewMouseDown"/>
        </Style>
    
        <!-- Declare a hierarchical data template for the tree view items -->
        <HierarchicalDataTemplate
            x:Key="RecursiveTemplate"
            ItemsSource="{Binding Children}">
    
            <StackPanel Margin="2" Orientation="Horizontal" MouseDown="OnTreeMouseDown">
                <Ellipse Width="12" Height="12" Fill="Green"/>
                <TextBlock
                    Margin="2"
                    Text="{Binding Name}"
                    Visibility="{Binding Editing, Converter={StaticResource visibilityInverter}}"/>
                <TextBox
                    Margin="2"
                    Text="{Binding Name}"
                    KeyDown="OnTextBoxKeyDown"
                    IsVisibleChanged="OnTextBoxIsVisibleChanged"
                    Visibility="{Binding Editing, Converter={StaticResource visibilityConverter}}"/>
                <TextBlock
                    Margin="2"
                    Text="{Binding Index, StringFormat=({0})}"/>
            </StackPanel>
    
        </HierarchicalDataTemplate>
    
        <!-- Declare a simple template for a list box -->
        <DataTemplate x:Key="ListTemplate">
            <TextBlock Text="{Binding Name}"/>
        </DataTemplate>
    
    </Window.Resources>
    
    <Grid>
    
        <!-- Declare the rows in this grid -->
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
    
        <!-- The first header -->
        <TextBlock Grid.Row="0" Margin="5" Background="PowderBlue">Multiple selection tree view</TextBlock>
    
        <!-- The tree view -->
        <TreeView
            Name="m_tree"
            Margin="2"
            Grid.Row="1"
            ItemsSource="{Binding Children}"
            ItemTemplate="{StaticResource RecursiveTemplate}"/>
    
        <!-- The second header -->
        <TextBlock Grid.Row="2" Margin="5" Background="PowderBlue">The currently selected items in the tree</TextBlock>
    
        <!-- The list box -->
        <ListBox 
            Name="m_list"
            Margin="2"
            Grid.Row="3"
            ItemsSource="{Binding .}"
            ItemTemplate="{StaticResource ListTemplate}"/>
    
    </Grid>
    
    </Window>
    

    主窗口.xaml.cs

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private Container m_root;
        private Container m_first;
        private ObservableCollection<Container> m_selection;
        private string m_current;
    
        /// <summary>
        /// Constructor
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
    
            m_selection = new ObservableCollection<Container>();
    
            m_root = new Container("root");
    
            for (int parents = 0; parents < 50; parents++)
            {
                Container parent = new Container(String.Format("parent{0}", parents + 1));
    
                for (int children = 0; children < 1000; children++)
                {
                    parent.Add(new Container(String.Format("child{0}", children + 1)));
                }
    
                m_root.Add(parent);
            }
    
            m_tree.DataContext = m_root;
            m_list.DataContext = m_selection;
            m_first = null;
        }
    
        /// <summary>
        /// Has the shift key been pressed?
        /// </summary>
        private bool ShiftPressed
        {
            get
            {
                return Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
            }
        }
    
        /// <summary>
        /// Has the control key been pressed?
        /// </summary>
        private bool CtrlPressed
        {
            get
            {
                return Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
            }
        }
    
        /// <summary>
        /// Clear down the selection list
        /// </summary>
        private void DeselectAndClear()
        {
            foreach(Container container in m_selection)
            {
                container.Selected = false;
            }
    
            m_selection.Clear();
        }
    
        /// <summary>
        /// Add the container to the list (if not already present),
        /// mark as selected
        /// </summary>
        /// <param name="container"></param>
        private void AddToSelection(Container container)
        {
            if (container == null)
            {
                return;
            }
    
            foreach (Container child in m_selection)
            {
                if (child == container)
                {
                    return;
                }
            }
    
            container.Selected = true;
    
            m_selection.Add(container);
        }
    
        /// <summary>
        /// Remove container from list, mark as not selected
        /// </summary>
        /// <param name="container"></param>
        private void RemoveFromSelection(Container container)
        {
            m_selection.Remove(container);
    
            container.Selected = false;
        }
    
        /// <summary>
        /// Process single click on a tree item
        /// 
        /// Normally just select an item
        /// 
        /// SHIFT-Click extends selection
        /// CTRL-Click toggles a selection
        /// </summary>
        /// <param name="sender"></param>
        private void OnTreeSingleClick(object sender)
        {
            FrameworkElement element = sender as FrameworkElement;
    
            if (element != null)
            {
                Container container = element.DataContext as Container;
    
                if (container != null)
                {
                    if (CtrlPressed)
                    {
                        if (container.Selected)
                        {
                            RemoveFromSelection(container);
                        }
                        else
                        {
                            AddToSelection(container);
                        }
                    }
                    else if (ShiftPressed)
                    {
                        if (container.Parent == m_first.Parent)
                        {
                            if (container.Index < m_first.Index)
                            {
                                Container item = container;
    
                                for (int i = container.Index; i < m_first.Index; i++)
                                {
                                    AddToSelection(item);
    
                                    item = item.Next;
    
                                    if (item == null)
                                    {
                                        break;
                                    }
                                }
                            }
                            else if (container.Index > m_first.Index)
                            {
                                Container item = m_first;
    
                                for (int i = m_first.Index; i <= container.Index; i++)
                                {
                                    AddToSelection(item);
    
                                    item = item.Next;
    
                                    if (item == null)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        DeselectAndClear();
    
                        m_first = container;
    
                        AddToSelection(container);
                    }
                }
            }
        }
    
        /// <summary>
        /// Process double click on tree item
        /// </summary>
        /// <param name="sender"></param>
        private void OnTreeDoubleClick(object sender)
        {
            FrameworkElement element = sender as FrameworkElement;
    
            if (element != null)
            {
                Container container = element.DataContext as Container;
    
                if (container != null)
                {
                    container.Editing = true;
    
                    m_current = container.Name;
                }
            }
        }
    
        /// <summary>
        /// Clicked on the stack panel in the tree view
        /// 
        /// Double left click:
        /// 
        /// Switch to editing mode (flips visibility of textblock and textbox)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnTreeMouseDown(object sender, MouseButtonEventArgs e)
        {
            Debug.WriteLine("StackPanel mouse down");
    
            switch(e.ChangedButton)
            {
                case MouseButton.Left:
                    switch (e.ClickCount)
                    {
                        case 2:
                            OnTreeDoubleClick(sender);
    
                            e.Handled = true;
                            break;
                    }
                    break;
            }
        }
    
        /// <summary>
        /// Clicked on tree view item in tree
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnTreePreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            Debug.WriteLine("TreeViewItem preview mouse down");
    
            switch (e.ChangedButton)
            {
                case MouseButton.Left:
                    switch (e.ClickCount)
                    {
                        case 1:
                            {
                                // We've had a single click on a tree view item
                                // Unfortunately this is the WHOLE tree item, including the +/-
                                // symbol to the left. The tree doesn't do a selection, so we
                                // have to filter this out...
                                MouseDevice device = e.Device as MouseDevice;
    
                                Debug.WriteLine(String.Format("Tree item clicked on: {0}", device.DirectlyOver.GetType().ToString()));
    
                                // This is bad. The whole point of WPF is for the code
                                // not to know what the UI has - yet here we are testing for
                                // it as a workaround. Sigh...
                                if (device.DirectlyOver.GetType() != typeof(Path))
                                {
                                    OnTreeSingleClick(sender);
                                }
    
                                // Cannot say handled - if we do it stops the tree working!
                                //e.Handled = true;
                            }
                            break;
                    }
                    break;
            }
        }
    
        /// <summary>
        /// Key press in text box
        /// 
        /// Return key finishes editing
        /// Escape key finishes editing, restores original value (this doesn't work!)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnTextBoxKeyDown(object sender, KeyEventArgs e)
        {
            switch(e.Key)
            {
                case Key.Return:
                    {
                        TextBox box = sender as TextBox;
    
                        if (box != null)
                        {
                            Container container = box.DataContext as Container;
    
                            if (container != null)
                            {
                                container.Editing = false;
    
                                e.Handled = true;
                            }
                        }
                    }
                    break;
    
                case Key.Escape:
                    {
                        TextBox box = sender as TextBox;
    
                        if (box != null)
                        {
                            Container container = box.DataContext as Container;
    
                            if (container != null)
                            {
                                container.Editing = false;
    
                                container.Name = m_current;
    
                                e.Handled = true;
                            }
                        }
                    }
                    break;
            }
        }
    
        /// <summary>
        /// When text box becomes visible, grab focus and select all text in it.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnTextBoxIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            bool visible = (bool)e.NewValue;
    
            if (visible)
            {
                TextBox box = sender as TextBox;
    
                if (box != null)
                {
                    box.Focus();
    
                    box.SelectAll();
                }
            }
        }
    }
    

    这是集装箱舱

    public class Container : INotifyPropertyChanged
    {
        private string m_name;
        private ObservableCollection<Container> m_children;
        private Container m_parent;
    
        private bool m_selected;
        private bool m_editing;
    
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="name">name of object</param>
        public Container(string name)
        {
            m_name = name;
    
            m_children = new ObservableCollection<Container>();
    
            m_parent = null;
    
            m_selected = false;
            m_editing = false;
        }
    
        /// <summary>
        /// Name of object
        /// </summary>
        public string Name
        {
            get
            {
                return m_name;
            }
    
            set
            {
                if (m_name != value)
                {
                    m_name = value;
    
                    OnPropertyChanged("Name");
                }
            }
        }
    
        /// <summary>
        /// Index of object in parent's children
        /// 
        /// If there's no parent, the index is -1
        /// </summary>
        public int Index
        {
            get
            {
                if (m_parent != null)
                {
                    return m_parent.Children.IndexOf(this);
                }
    
                return -1;
            }
        }
    
        /// <summary>
        /// Get the next item, assuming this is parented
        /// 
        /// Returns null if end of list reached, or no parent
        /// </summary>
        public Container Next
        {
            get
            {
                if (m_parent != null)
                {
                    int index = Index + 1;
    
                    if (index < m_parent.Children.Count)
                    {
                        return m_parent.Children[index];
                    }
                }
    
                return null;
            }
        }
    
        /// <summary>
        /// List of children
        /// </summary>
        public ObservableCollection<Container> Children
        {
            get
            {
                return m_children;
            }
        }
    
        /// <summary>
        /// Selected status
        /// </summary>
        public bool Selected
        {
            get
            {
                return m_selected;
            }
    
            set
            {
                if (m_selected != value)
                {
                    m_selected = value;
    
                    OnPropertyChanged("Selected");
                }
            }
        }
    
        /// <summary>
        /// Editing status
        /// </summary>
        public bool Editing
        {
            get
            {
                return m_editing;
            }
    
            set
            {
                if (m_editing != value)
                {
                    m_editing = value;
    
                    OnPropertyChanged("Editing");
                }
            }
        }
    
        /// <summary>
        /// Parent of this object
        /// </summary>
        public Container Parent
        {
            get
            {
                return m_parent;
            }
    
            set
            {
                m_parent = value;
            }
        }
    
        /// <summary>
        /// WPF Property Changed event
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
    
        /// <summary>
        /// Handler to inform WPF that a property has changed
        /// </summary>
        /// <param name="name"></param>
        private void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    
        /// <summary>
        /// Add a child to this container
        /// </summary>
        /// <param name="child"></param>
        public void Add(Container child)
        {
            m_children.Add(child);
    
            child.m_parent = this;
        }
    
        /// <summary>
        /// Remove a child from this container
        /// </summary>
        /// <param name="child"></param>
        public void Remove(Container child)
        {
            m_children.Remove(child);
    
            child.m_parent = null;
        }
    }
    

    0 回复  |  直到 16 年前