AutoCompleteBox 弹出窗口内的 TreeView

发布于 2024-09-05 21:13:07 字数 537 浏览 4 评论 0原文

受到这篇文章的启发,我正在尝试使用AutoCompleteBox 弹出窗口内的 TreeView 以显示分层数据。

这就是我所做的:

  1. 我制作了自己的实现 ISelectionAdapter 的 TreeView(不确定它是否完美)

  2. 编辑 AutoCompleteBox 模板并更改选择器到我的树视图

  3. 尝试将我的 ViewModel 绑定到它

不幸的是,这不起作用。 我检查了我的新 TreeView 是否具有与同一对象的相同绑定,并且当它位于 AutoCompleteBox 模板之外时它可以正常工作。

有什么想法吗?有什么特殊的方法来实现树视图的 ISelectionAdapter 吗?我错过了什么吗?

在网上找不到任何示例...

谢谢。

Inspired by this post, I'm trying to use a TreeView inside the AutoCompleteBox's popup in order to show hierarchical data.

Here's what i did:

  1. I Made my own TreeView that implements ISelectionAdapter (not sure it's perfect)

  2. Edit AutoCompleteBox template and change the selector to my treeview

  3. Try Bind my ViewModel to it

Unfortunately this is not working.
i checked my new TreeView with the same binding to the same object and it works prefectly when it's outside of a AutoCompleteBox template.

Any idea? any special way to implement ISelectionAdapter for treeview? did i missed something?

couldn't find any example for it on the web...

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

狼性发作 2024-09-12 21:13:07

我最终成功地写了它。

为它做了一个自定义控件。它仍然需要改进,但效果很好:

Generic.xaml:

<ControlTemplate x:Key="CommonValidationToolTipTemplate" TargetType="ToolTip">
    <Grid x:Name="Root" Margin="5,0" Opacity="0" RenderTransformOrigin="0,0">
        <Grid.RenderTransform>
            <TranslateTransform x:Name="Translation" X="-25"/>
        </Grid.RenderTransform>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="OpenStates">
                <VisualStateGroup.Transitions>
                    <VisualTransition GeneratedDuration="0"/>
                    <VisualTransition GeneratedDuration="0:0:0.2" To="Open">
                        <Storyboard>
                            <DoubleAnimation Duration="0:0:0.2" To="0" Storyboard.TargetProperty="X" Storyboard.TargetName="Translation">
                                <DoubleAnimation.EasingFunction>
                                    <BackEase Amplitude=".3" EasingMode="EaseOut"/>
                                </DoubleAnimation.EasingFunction>
                            </DoubleAnimation>
                            <DoubleAnimation Duration="0:0:0.2" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/>
                        </Storyboard>
                    </VisualTransition>
                </VisualStateGroup.Transitions>
                <VisualState x:Name="Closed">
                    <Storyboard>
                        <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Open">
                    <Storyboard>
                        <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="X" Storyboard.TargetName="Translation"/>
                        <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Border Background="#052A2E31" CornerRadius="5" Margin="4,4,-4,-4"/>
        <Border Background="#152A2E31" CornerRadius="4" Margin="3,3,-3,-3"/>
        <Border Background="#252A2E31" CornerRadius="3" Margin="2,2,-2,-2"/>
        <Border Background="#352A2E31" CornerRadius="2" Margin="1,1,-1,-1"/>
        <Border Background="#FFDC000C" CornerRadius="2">
            <TextBlock Foreground="White" MaxWidth="250" Margin="8,4,8,4" TextWrapping="Wrap" Text="{Binding (Validation.Errors)[0].ErrorContent}" UseLayoutRounding="false"/>
        </Border>
    </Grid>
</ControlTemplate>
<Style TargetType="local:AutoCompleteTreeView"
       xmlns:System="clr-namespace:System;assembly=mscorlib">
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="Padding" Value="2"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="BorderBrush">
        <Setter.Value>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FFA3AEB9" Offset="0"/>
                <GradientStop Color="#FF8399A9" Offset="0.375"/>
                <GradientStop Color="#FF718597" Offset="0.375"/>
                <GradientStop Color="#FF617584" Offset="1"/>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
    <Setter Property="Background" Value="#FFFFFFFF"/>
    <Setter Property="Foreground" Value="#FF000000"/>
    <Setter Property="MinWidth" Value="45"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:AutoCompleteTreeView">
                <Grid Opacity="{TemplateBinding Opacity}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="PopupStates">
                            <VisualStateGroup.Transitions>
                                <VisualTransition GeneratedDuration="0:0:0.1" To="PopupOpened"/>
                                <VisualTransition GeneratedDuration="0:0:0.2" To="PopupClosed"/>
                            </VisualStateGroup.Transitions>
                            <VisualState x:Name="PopupOpened">
                                <Storyboard>
                                    <DoubleAnimation To="1.0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PopupBorder"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="PopupClosed">
                                <Storyboard>
                                    <DoubleAnimation To="0.0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PopupBorder"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="ValidationStates">
                            <VisualState x:Name="Valid"/>
                            <VisualState x:Name="InvalidUnfocused">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationErrorElement">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="InvalidFocused">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationErrorElement">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsOpen" Storyboard.TargetName="validationTooltip">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <System:Boolean>True</System:Boolean>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <TextBox x:Name="Text" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" IsTabStop="True" Margin="0" Padding="{TemplateBinding Padding}" Style="{TemplateBinding TextBoxStyle}"/>
                    <Border x:Name="ValidationErrorElement" BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1" Visibility="Collapsed">
                        <ToolTipService.ToolTip>
                            <ToolTip x:Name="validationTooltip" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{StaticResource CommonValidationToolTipTemplate}">
                                <ToolTip.Triggers>
                                    <EventTrigger RoutedEvent="Canvas.Loaded">
                                        <BeginStoryboard>
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="validationTooltip">
                                                    <DiscreteObjectKeyFrame KeyTime="0">
                                                        <DiscreteObjectKeyFrame.Value>
                                                            <System:Boolean>true</System:Boolean>
                                                        </DiscreteObjectKeyFrame.Value>
                                                    </DiscreteObjectKeyFrame>
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </EventTrigger>
                                </ToolTip.Triggers>
                            </ToolTip>
                        </ToolTipService.ToolTip>
                        <Grid Background="Transparent" HorizontalAlignment="Right" Height="12" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12">
                            <Path Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C" Margin="1,3,0,0"/>
                            <Path Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff" Margin="1,3,0,0"/>
                        </Grid>
                    </Border>
                    <Popup x:Name="Popup">
                        <Grid Opacity="{TemplateBinding Opacity}">
                            <Border x:Name="PopupBorder" BorderThickness="0" Background="#11000000" HorizontalAlignment="Stretch" Opacity="0">
                                <Border.RenderTransform>
                                    <TranslateTransform X="1" Y="1"/>
                                </Border.RenderTransform>
                                <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="0" HorizontalAlignment="Stretch" Opacity="1.0" Padding="0">
                                    <Border.Background>
                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                            <GradientStop Color="#FFDDDDDD" Offset="0"/>
                                            <GradientStop Color="#AADDDDDD" Offset="1"/>
                                        </LinearGradientBrush>
                                    </Border.Background>
                                    <Border.RenderTransform>
                                        <TransformGroup>
                                            <TranslateTransform X="-1" Y="-1"/>
                                        </TransformGroup>
                                    </Border.RenderTransform>
                                    <local:TreeViewSelectionAdapter x:Name="SelectionAdapter" BorderThickness="0" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" ScrollViewer.HorizontalScrollBarVisibility="Auto" ItemTemplate="{TemplateBinding ItemTemplate}" ItemContainerStyle="{TemplateBinding ItemContainerStyle}" ScrollViewer.VerticalScrollBarVisibility="Auto"/>
                                </Border>  
                            </Border>  
                        </Grid>
                    </Popup>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

AutoCompleteTreeView.cs:

public class AutoCompleteTreeView : AutoCompleteBox
{
    public AutoCompleteTreeView()
    {
        DefaultStyleKey = typeof(AutoCompleteTreeView);
    }
}

TreeViewSelectionAdapter.cs:

public class TreeViewSelectionAdapter : TreeView, ISelectionAdapter
{
    private object lastSelectedItem = null;

    /// <summary>
    ///This prevents the text box of the AutoCompleteBox control from being updated continuously.
    /// </summary>
    private bool IgnoreAnySelection { get; set; }

    /// <summary>
    /// An event that indicates that a selection is complete and has been
    /// made, effectively a commit action.
    /// </summary>
    public event RoutedEventHandler Commit;

    /// <summary>
    /// An event that indicates that the selection operation has been
    /// canceled.
    /// </summary>
    public event RoutedEventHandler Cancel;

    /// <summary>
    /// Initializes a new instance of the SelectorSelectionAdapter class.
    /// </summary>
    public TreeViewSelectionAdapter()
    {
        base.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(OnSelectionChanged);
        MouseLeftButtonUp += OnSelectorMouseLeftButtonUp;

    }

    void OnSelectionChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {

        if (IgnoreAnySelection)
        {
            return;
        }

        SelectionChangedEventHandler handler = this.SelectionChanged;
        if (handler != null)
        {
            IList oldSelectedItem = new List<object>();
            if (lastSelectedItem != null)
                oldSelectedItem.Add(lastSelectedItem);

            if (SelectionChanged != null)
                handler(this, new SelectionChangedEventArgs(oldSelectedItem, new List<object> { this.SelectedItem }));

            lastSelectedItem = this.SelectedItem;

        }
    }

    public new object SelectedItem
    {
        get
        {
            return base.SelectedItem;
        }

        set
        {
            this.SelectItem(value);
        }
    }

    /// <summary>
    /// Handles the mouse left button up event on the selector control.
    /// </summary>
    private void OnSelectorMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        IgnoreAnySelection = false;

        OnSelectionChanged(this, null);
        OnCommit(this, new RoutedEventArgs());
    }


    public event SelectionChangedEventHandler SelectionChanged;



    /// <summary>
    /// Gets or sets the items source.
    /// </summary>
    public new IEnumerable ItemsSource
    {
        get { return base.ItemsSource; }

        set
        {
            if (base.ItemsSource != null)
            {
                INotifyCollectionChanged notify = base.ItemsSource as INotifyCollectionChanged;
                if (notify != null)
                {
                    notify.CollectionChanged -= OnCollectionChanged;
                }
            }

            base.ItemsSource = value;

            if (base.ItemsSource != null)
            {
                INotifyCollectionChanged notify = base.ItemsSource as INotifyCollectionChanged;
                if (notify != null)
                {
                    notify.CollectionChanged += OnCollectionChanged;
                }
            }
        }
    }

    /// <summary>
    /// Handles the CollectionChanged event, resetting the selection
    /// ignore flag.
    /// </summary>
    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        IgnoreAnySelection = true;
    }


    /// <summary>
    /// Process a key down event.
    /// </summary>
    public void HandleKeyDown(KeyEventArgs e)
    {
        switch (e.Key)
        {
            case Key.Enter:
                IgnoreAnySelection = false;
                OnCommit(this, e);
                e.Handled = true;
                break;


            case Key.Down:
                if ((ModifierKeys.Alt & Keyboard.Modifiers) == ModifierKeys.None)
                {
                    IgnoreAnySelection = true;
                    //SelectedIndexIncrement();
                    TreeView tv = this.FindName("SelectionAdapter") as TreeView;

                    tv.KeyDown += new KeyEventHandler(tv_KeyDown);
                    tv.Focus();

                    List<TreeViewItem> ls = new List<TreeViewItem>(tv.GetContainers());
                    ls[0].Focus();
                    e.Handled = true;

                }
                break;

            case Key.Escape:
                OnCancel(this, e);
                e.Handled = true;
                break;

            default:
                break;
        }
    }

    void tv_KeyDown(object sender, KeyEventArgs e)
    {
        switch (e.Key)
        {
            case Key.Enter:

                IgnoreAnySelection = false;

                OnSelectionChanged(this, null);
                OnCommit(this, new RoutedEventArgs());
                break;
        }
    }



    /// <summary>
    /// Fires the Commit event.
    /// </summary>
    private void OnCommit(object sender, RoutedEventArgs e)
    {
        RoutedEventHandler handler = Commit;
        if (handler != null)
        {
            handler(sender, e);
        }

        AfterAdapterAction();
    }

    /// <summary>
    /// Fires the Cancel event.
    /// </summary>
    private void OnCancel(object sender, RoutedEventArgs e)
    {
        RoutedEventHandler handler = Cancel;
        if (handler != null)
        {
            handler(sender, e);
        }

        AfterAdapterAction();
    }

    /// <summary>
    /// Change the selection after the actions are complete.
    /// </summary>
    private void AfterAdapterAction()
    {
        this.SetSelectedContainer(null);
    }

    /// <summary>
    /// Initializes a new instance of a DataGridAutomationPeer.
    /// </summary>
    public AutomationPeer CreateAutomationPeer()
    {
        return new TreeViewAutomationPeer(this);
    }
}

使用控件:

<ccontrols:AutoCompleteTreeView  x:Name="textbox" MinimumPrefixLength="1" IsEnabled="True" ItemsSource="{Binding MyNodes}"  >
        <ccontrols:AutoCompleteTreeView.ItemTemplate>
            <hirarch:HierarchicalDataTemplate ItemsSource="{Binding MyNodes}" >
                <TextBlock Text="{Binding Name}" />
            </hirarch:HierarchicalDataTemplate>
        </ccontrols:AutoCompleteTreeView.ItemTemplate>
    </ccontrols:AutoCompleteTreeView>

层次结构对象:

public class Node
{
    public string Name { get; set; }
    public List<Node> MyNodes { get; set; }

    public override string ToString()
    {
        return Name;
    }
}

I managed to write it eventually.

Made a custom control for it. it still need to be refined, but it works good:

Generic.xaml :

<ControlTemplate x:Key="CommonValidationToolTipTemplate" TargetType="ToolTip">
    <Grid x:Name="Root" Margin="5,0" Opacity="0" RenderTransformOrigin="0,0">
        <Grid.RenderTransform>
            <TranslateTransform x:Name="Translation" X="-25"/>
        </Grid.RenderTransform>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="OpenStates">
                <VisualStateGroup.Transitions>
                    <VisualTransition GeneratedDuration="0"/>
                    <VisualTransition GeneratedDuration="0:0:0.2" To="Open">
                        <Storyboard>
                            <DoubleAnimation Duration="0:0:0.2" To="0" Storyboard.TargetProperty="X" Storyboard.TargetName="Translation">
                                <DoubleAnimation.EasingFunction>
                                    <BackEase Amplitude=".3" EasingMode="EaseOut"/>
                                </DoubleAnimation.EasingFunction>
                            </DoubleAnimation>
                            <DoubleAnimation Duration="0:0:0.2" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/>
                        </Storyboard>
                    </VisualTransition>
                </VisualStateGroup.Transitions>
                <VisualState x:Name="Closed">
                    <Storyboard>
                        <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Open">
                    <Storyboard>
                        <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="X" Storyboard.TargetName="Translation"/>
                        <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Border Background="#052A2E31" CornerRadius="5" Margin="4,4,-4,-4"/>
        <Border Background="#152A2E31" CornerRadius="4" Margin="3,3,-3,-3"/>
        <Border Background="#252A2E31" CornerRadius="3" Margin="2,2,-2,-2"/>
        <Border Background="#352A2E31" CornerRadius="2" Margin="1,1,-1,-1"/>
        <Border Background="#FFDC000C" CornerRadius="2">
            <TextBlock Foreground="White" MaxWidth="250" Margin="8,4,8,4" TextWrapping="Wrap" Text="{Binding (Validation.Errors)[0].ErrorContent}" UseLayoutRounding="false"/>
        </Border>
    </Grid>
</ControlTemplate>
<Style TargetType="local:AutoCompleteTreeView"
       xmlns:System="clr-namespace:System;assembly=mscorlib">
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="Padding" Value="2"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="BorderBrush">
        <Setter.Value>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FFA3AEB9" Offset="0"/>
                <GradientStop Color="#FF8399A9" Offset="0.375"/>
                <GradientStop Color="#FF718597" Offset="0.375"/>
                <GradientStop Color="#FF617584" Offset="1"/>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
    <Setter Property="Background" Value="#FFFFFFFF"/>
    <Setter Property="Foreground" Value="#FF000000"/>
    <Setter Property="MinWidth" Value="45"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:AutoCompleteTreeView">
                <Grid Opacity="{TemplateBinding Opacity}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="PopupStates">
                            <VisualStateGroup.Transitions>
                                <VisualTransition GeneratedDuration="0:0:0.1" To="PopupOpened"/>
                                <VisualTransition GeneratedDuration="0:0:0.2" To="PopupClosed"/>
                            </VisualStateGroup.Transitions>
                            <VisualState x:Name="PopupOpened">
                                <Storyboard>
                                    <DoubleAnimation To="1.0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PopupBorder"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="PopupClosed">
                                <Storyboard>
                                    <DoubleAnimation To="0.0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PopupBorder"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="ValidationStates">
                            <VisualState x:Name="Valid"/>
                            <VisualState x:Name="InvalidUnfocused">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationErrorElement">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="InvalidFocused">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationErrorElement">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsOpen" Storyboard.TargetName="validationTooltip">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <System:Boolean>True</System:Boolean>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <TextBox x:Name="Text" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" IsTabStop="True" Margin="0" Padding="{TemplateBinding Padding}" Style="{TemplateBinding TextBoxStyle}"/>
                    <Border x:Name="ValidationErrorElement" BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1" Visibility="Collapsed">
                        <ToolTipService.ToolTip>
                            <ToolTip x:Name="validationTooltip" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{StaticResource CommonValidationToolTipTemplate}">
                                <ToolTip.Triggers>
                                    <EventTrigger RoutedEvent="Canvas.Loaded">
                                        <BeginStoryboard>
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="validationTooltip">
                                                    <DiscreteObjectKeyFrame KeyTime="0">
                                                        <DiscreteObjectKeyFrame.Value>
                                                            <System:Boolean>true</System:Boolean>
                                                        </DiscreteObjectKeyFrame.Value>
                                                    </DiscreteObjectKeyFrame>
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </EventTrigger>
                                </ToolTip.Triggers>
                            </ToolTip>
                        </ToolTipService.ToolTip>
                        <Grid Background="Transparent" HorizontalAlignment="Right" Height="12" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12">
                            <Path Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C" Margin="1,3,0,0"/>
                            <Path Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff" Margin="1,3,0,0"/>
                        </Grid>
                    </Border>
                    <Popup x:Name="Popup">
                        <Grid Opacity="{TemplateBinding Opacity}">
                            <Border x:Name="PopupBorder" BorderThickness="0" Background="#11000000" HorizontalAlignment="Stretch" Opacity="0">
                                <Border.RenderTransform>
                                    <TranslateTransform X="1" Y="1"/>
                                </Border.RenderTransform>
                                <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="0" HorizontalAlignment="Stretch" Opacity="1.0" Padding="0">
                                    <Border.Background>
                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                            <GradientStop Color="#FFDDDDDD" Offset="0"/>
                                            <GradientStop Color="#AADDDDDD" Offset="1"/>
                                        </LinearGradientBrush>
                                    </Border.Background>
                                    <Border.RenderTransform>
                                        <TransformGroup>
                                            <TranslateTransform X="-1" Y="-1"/>
                                        </TransformGroup>
                                    </Border.RenderTransform>
                                    <local:TreeViewSelectionAdapter x:Name="SelectionAdapter" BorderThickness="0" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" ScrollViewer.HorizontalScrollBarVisibility="Auto" ItemTemplate="{TemplateBinding ItemTemplate}" ItemContainerStyle="{TemplateBinding ItemContainerStyle}" ScrollViewer.VerticalScrollBarVisibility="Auto"/>
                                </Border>  
                            </Border>  
                        </Grid>
                    </Popup>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

AutoCompleteTreeView.cs:

public class AutoCompleteTreeView : AutoCompleteBox
{
    public AutoCompleteTreeView()
    {
        DefaultStyleKey = typeof(AutoCompleteTreeView);
    }
}

TreeViewSelectionAdapter.cs:

public class TreeViewSelectionAdapter : TreeView, ISelectionAdapter
{
    private object lastSelectedItem = null;

    /// <summary>
    ///This prevents the text box of the AutoCompleteBox control from being updated continuously.
    /// </summary>
    private bool IgnoreAnySelection { get; set; }

    /// <summary>
    /// An event that indicates that a selection is complete and has been
    /// made, effectively a commit action.
    /// </summary>
    public event RoutedEventHandler Commit;

    /// <summary>
    /// An event that indicates that the selection operation has been
    /// canceled.
    /// </summary>
    public event RoutedEventHandler Cancel;

    /// <summary>
    /// Initializes a new instance of the SelectorSelectionAdapter class.
    /// </summary>
    public TreeViewSelectionAdapter()
    {
        base.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(OnSelectionChanged);
        MouseLeftButtonUp += OnSelectorMouseLeftButtonUp;

    }

    void OnSelectionChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {

        if (IgnoreAnySelection)
        {
            return;
        }

        SelectionChangedEventHandler handler = this.SelectionChanged;
        if (handler != null)
        {
            IList oldSelectedItem = new List<object>();
            if (lastSelectedItem != null)
                oldSelectedItem.Add(lastSelectedItem);

            if (SelectionChanged != null)
                handler(this, new SelectionChangedEventArgs(oldSelectedItem, new List<object> { this.SelectedItem }));

            lastSelectedItem = this.SelectedItem;

        }
    }

    public new object SelectedItem
    {
        get
        {
            return base.SelectedItem;
        }

        set
        {
            this.SelectItem(value);
        }
    }

    /// <summary>
    /// Handles the mouse left button up event on the selector control.
    /// </summary>
    private void OnSelectorMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        IgnoreAnySelection = false;

        OnSelectionChanged(this, null);
        OnCommit(this, new RoutedEventArgs());
    }


    public event SelectionChangedEventHandler SelectionChanged;



    /// <summary>
    /// Gets or sets the items source.
    /// </summary>
    public new IEnumerable ItemsSource
    {
        get { return base.ItemsSource; }

        set
        {
            if (base.ItemsSource != null)
            {
                INotifyCollectionChanged notify = base.ItemsSource as INotifyCollectionChanged;
                if (notify != null)
                {
                    notify.CollectionChanged -= OnCollectionChanged;
                }
            }

            base.ItemsSource = value;

            if (base.ItemsSource != null)
            {
                INotifyCollectionChanged notify = base.ItemsSource as INotifyCollectionChanged;
                if (notify != null)
                {
                    notify.CollectionChanged += OnCollectionChanged;
                }
            }
        }
    }

    /// <summary>
    /// Handles the CollectionChanged event, resetting the selection
    /// ignore flag.
    /// </summary>
    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        IgnoreAnySelection = true;
    }


    /// <summary>
    /// Process a key down event.
    /// </summary>
    public void HandleKeyDown(KeyEventArgs e)
    {
        switch (e.Key)
        {
            case Key.Enter:
                IgnoreAnySelection = false;
                OnCommit(this, e);
                e.Handled = true;
                break;


            case Key.Down:
                if ((ModifierKeys.Alt & Keyboard.Modifiers) == ModifierKeys.None)
                {
                    IgnoreAnySelection = true;
                    //SelectedIndexIncrement();
                    TreeView tv = this.FindName("SelectionAdapter") as TreeView;

                    tv.KeyDown += new KeyEventHandler(tv_KeyDown);
                    tv.Focus();

                    List<TreeViewItem> ls = new List<TreeViewItem>(tv.GetContainers());
                    ls[0].Focus();
                    e.Handled = true;

                }
                break;

            case Key.Escape:
                OnCancel(this, e);
                e.Handled = true;
                break;

            default:
                break;
        }
    }

    void tv_KeyDown(object sender, KeyEventArgs e)
    {
        switch (e.Key)
        {
            case Key.Enter:

                IgnoreAnySelection = false;

                OnSelectionChanged(this, null);
                OnCommit(this, new RoutedEventArgs());
                break;
        }
    }



    /// <summary>
    /// Fires the Commit event.
    /// </summary>
    private void OnCommit(object sender, RoutedEventArgs e)
    {
        RoutedEventHandler handler = Commit;
        if (handler != null)
        {
            handler(sender, e);
        }

        AfterAdapterAction();
    }

    /// <summary>
    /// Fires the Cancel event.
    /// </summary>
    private void OnCancel(object sender, RoutedEventArgs e)
    {
        RoutedEventHandler handler = Cancel;
        if (handler != null)
        {
            handler(sender, e);
        }

        AfterAdapterAction();
    }

    /// <summary>
    /// Change the selection after the actions are complete.
    /// </summary>
    private void AfterAdapterAction()
    {
        this.SetSelectedContainer(null);
    }

    /// <summary>
    /// Initializes a new instance of a DataGridAutomationPeer.
    /// </summary>
    public AutomationPeer CreateAutomationPeer()
    {
        return new TreeViewAutomationPeer(this);
    }
}

Using the control:

<ccontrols:AutoCompleteTreeView  x:Name="textbox" MinimumPrefixLength="1" IsEnabled="True" ItemsSource="{Binding MyNodes}"  >
        <ccontrols:AutoCompleteTreeView.ItemTemplate>
            <hirarch:HierarchicalDataTemplate ItemsSource="{Binding MyNodes}" >
                <TextBlock Text="{Binding Name}" />
            </hirarch:HierarchicalDataTemplate>
        </ccontrols:AutoCompleteTreeView.ItemTemplate>
    </ccontrols:AutoCompleteTreeView>

The hierarchy objects:

public class Node
{
    public string Name { get; set; }
    public List<Node> MyNodes { get; set; }

    public override string ToString()
    {
        return Name;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文