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>
浙公网安备 33010602011771号