WPF 实现搜索机构树,定位到搜索节点,并递归展开父级节点,滚动条滚动到此节点(包含水印控件 mvvm)

 搜索机构树,选中搜索机构树后定位,展开父级,滚动条滚动到相应位置,一条龙

 

废话不多说,直接上源码

 xaml

     <StackPanel x:Name="panel" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="15 0">
                    <control:WaterMarkTextBox Style="{StaticResource WaterMarkTextBox}" WaterMark="搜索机构" x:Name="searchTexbox" MaxHeight="50" Width="300" VerticalContentAlignment="Center">
                        <control:WaterMarkTextBox.InputBindings>
                            <KeyBinding Key="Enter" Command="{Binding SearchCommand}" CommandParameter="{Binding Text,ElementName=searchTexbox}"/>
                        </control:WaterMarkTextBox.InputBindings>
                    </control:WaterMarkTextBox>
                    <Button Command="{Binding SearchCommand}" CommandParameter="{Binding Text,ElementName=searchTexbox}" Style="{StaticResource ButtonStyle}" Width="50" Margin="3 0 0 0" Content="搜索"/>
                    <Popup  Width="{Binding ActualWidth,ElementName=panel}" IsOpen="{Binding IsDropOpen}" AllowsTransparency="True"   StaysOpen="False" PlacementTarget="{Binding ElementName=searchTexbox}" >
                        <Border BorderBrush="#CCCCCC" BorderThickness="1" Background="Gray" Height="300" Width="{Binding ActualWidth,ElementName=panel}">
                            <ListView VerticalContentAlignment="Center"  BorderThickness="0" x:Name="listview" ItemsSource="{Binding SearchOrgs}" ItemTemplate="{StaticResource serachOrgItemTemplate}">
                            </ListView>
                        </Border>
                    </Popup>
                </StackPanel>

水印控件可以替换textbox

  <TreeView   x:Name="tree" VerticalContentAlignment="Center" BorderBrush="#CCCCCC" BorderThickness="1" HorizontalAlignment="Stretch"   ScrollViewer.CanContentScroll="False" ItemsSource="{Binding OrgModels}"  ItemContainerStyle="{StaticResource TreeViewItemContainerStyle1}"   ItemTemplate="{StaticResource ResourceKey=treeItemTemplate}"  Grid.Row="1" Grid.Column="0"  
                          Margin="15 3 0 3"  >
                        <i:Interaction.Triggers>
                                <i:EventTrigger EventName="SelectedItemChanged">
                                    <i:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}" CommandParameter="{Binding SelectedItem,ElementName=tree}">
                                    </i:InvokeCommandAction>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </TreeView>

    <Style x:Key="TreeViewItemContainerStyle1" TargetType="{x:Type TreeViewItem}">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="Padding" Value="1,0,0,0"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
        <Setter Property="IsSelected" Value="{Binding IsSelected,Mode=TwoWay}"/>
        <Setter Property="IsExpanded" Value="{Binding IsExpland,Mode=TwoWay}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TreeViewItem}">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition MinWidth="20" Width="Auto"/>
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="30"/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <Border SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"  Margin="-1600 0 0 0" x:Name="border"   
                                 Grid.ColumnSpan="2">
                        </Border>
                        <ToggleButton x:Name="Expander" VerticalAlignment="Center" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
                        <ContentPresenter  Grid.Column="1" VerticalAlignment="Stretch"  x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="Stretch" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        <ItemsPresenter HorizontalAlignment="Stretch" x:Name="ItemsHost"  Grid.Column="1"  Grid.Row="1"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsExpanded" Value="false">
                            <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
                        </Trigger>
                        <Trigger Property="HasItems" Value="false">
                            <Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
                        </Trigger>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter Property="Background" TargetName="border" Value="lightblue"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true">
                <Setter Property="ItemsPanel">
                    <Setter.Value>
                        <ItemsPanelTemplate>
                            <VirtualizingStackPanel/>
                        </ItemsPanelTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>

    <HierarchicalDataTemplate x:Key="treeItemTemplate" ItemsSource="{Binding Children}">
        <Label VerticalContentAlignment="Center" Margin="0 0 0 0"  Content="{Binding Name}"/>
    </HierarchicalDataTemplate>


    <DataTemplate x:Key="serachOrgItemTemplate">
        <Grid  VerticalAlignment="Center" Height="28" >
            <TextBlock Width="220" VerticalAlignment="Center"  TextAlignment="Left"  Text="{Binding Name}" >
            </TextBlock>
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseDown">//这里用mousedown事件不好用,应该直接用listview的selectedchanged事件
                    <i:InvokeCommandAction Command="{Binding DataContext.SearchOrgChangedCommand,ElementName=view}" CommandParameter="{Binding}">
                    </i:InvokeCommandAction>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Grid>
    </DataTemplate>

上面是需要用到的样式

查询命令

      public RelayCommand<string> SearchCommand
        {
            get
            {
                return new RelayCommand<string>(new Action<string>((searchTxt) =>
               {
                   try
                   {
                       IsDropOpen = true;
                       var temp = OrgModelsList.FindAll(o => o.Name.Contains(searchTxt));
                       SearchOrgs = new ObservableCollection<OrgModel>(temp);
                   }
                   catch (Exception ex)
                   {
                       MessageBox.Show(ex.Message);
                   }

               }));
            }
        }

 

查询完后下拉选择项命令 核心部分

 

     public RelayCommand<object> SearchOrgChangedCommand
        {
            get
            {
                return new RelayCommand<object>((obj) =>
                {
                    try
                    {
                        IsDropOpen = false;
                        var org = obj as OrgModel;
                        if (org == null)
                            return;
                        //递归找到树节点
                        var temp = OrgModelsList.Find(o => o.DataModel.ID == org.DataModel.ID);
                        if (temp != null)
                        {
                            UnExpland();
                            ExplandParent(temp);
                            temp.IsSelected = true;
                            TreeViewAutomationPeer treePeer = new TreeViewAutomationPeer(View.tree);//拿到tree控件
                            var scrollPeer = treePeer.GetPattern(PatternInterface.Scroll) as ScrollViewerAutomationPeer;
                            var scroll = scrollPeer.Owner as ScrollViewer;
                            //计算偏移量
                            _preCount = 0;
                            _laterCount = 0;
                            NodesCount(temp);//计算选择的行前后分别共有有多少条
                            if (_laterCount == 0)
                            {
                                scroll.ScrollToBottom();
                                return;
                            }
                            scroll.ScrollToVerticalOffset((_preCount-5)*30);//向上找5个后,计算滚动条,偏移高度(30是treeviewItem行高)
                        }
                        
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }

                });
            }
        }

 

        private int _preCount;
        private int _laterCount;
  

//计算选择的行前后分别共有有多少条
        private void NodesCount(OrgModel orgModel)
        {
            var parent = OrgModelsList.Find(o => o.DataModel.ID == orgModel.DataModel.ParentId);
            if (parent == null)
                return ;
           var index= parent.Children.IndexOf(orgModel);
            _preCount = _preCount+index + 1;
            _laterCount =_laterCount+parent.Children.Count - index+1;
            NodesCount(parent);
        }

        /// <summary>
        /// 折叠所有机构树
        /// </summary>
        public void UnExpland()
        {
            foreach (var item in OrgModelsList)
            {
                item.IsSelected = false;
                item.IsExpland = false;
            }
        }

 

//展开所有父级节点

        public void ExplandParent(OrgModel orgModel)
        {
            var parent = OrgModelsList.Find(o => o.DataModel.ID == orgModel.DataModel.ParentId);
            if (parent == null)
                return;
            parent.IsExpland = true;
            ExplandParent(parent);
        }


附水印控件

 public class WaterMarkTextBox:TextBox
    {

        public string WaterMark
        {
            get { return (string)GetValue(WaterMarkProperty); }
            set { SetValue(WaterMarkProperty, value); }
        }
   
        public static readonly System.Windows.DependencyProperty WaterMarkProperty =
            DependencyProperty.Register("WaterMark", typeof(string), typeof(WaterMarkTextBox));
    }

水印控件样式

  <Style TargetType="{x:Type control:WaterMarkTextBox}" x:Key="WaterMarkTextBox">
        <Setter Property="Height" Value="30"/>
        <Setter Property="FontSize" Value="12"/>
        <Setter Property="MaxLength" Value="20"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="TextBox">
                    <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                        <Grid>
                            <TextBlock Text="{Binding WaterMark,RelativeSource={RelativeSource AncestorType={x:Type control:WaterMarkTextBox}}}"  VerticalAlignment="Center" HorizontalAlignment="Left" Foreground="Silver" Name="markText" Visibility="Collapsed" FontSize="12" Margin="10,0"/>
                            <ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"  VerticalAlignment="Center" MinHeight="20"/>
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Opacity" TargetName="border" Value="0.56"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
                        </Trigger>
                        <Trigger Property="IsKeyboardFocused" Value="true">
                            <Setter Property="BorderBrush" TargetName="border" Value="#FF569DE5"/>
                        </Trigger>
                        <DataTrigger Binding="{Binding Path=Text,RelativeSource={RelativeSource Mode=self}}" Value="">
                            <Setter Property="Visibility" TargetName="markText" Value="Visible"/>
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

 

posted @ 2022-08-24 12:58  心中的日月123  阅读(810)  评论(0)    收藏  举报