今天在开发的过程中突然碰到了一个问题,本来的意图是想当ItemsControl中加载的Item达到一定数量时,会出现ScrollViewer并出现垂直的滚动条,但是实际上并不能够达成目标,对于熟手来说这个问题非常简单,但是如果不了解WPF的模板的原理,可能并不清楚这些,这里举出一个例子来论证。

<Window x:Class="TestItemsControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="ItemsControlStyle1" TargetType="{x:Type ItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ItemsControl Width="100"
Height="100"
Background="Teal"
Style="{DynamicResource ItemsControlStyle1}">
<TextBox Text="1" Foreground="Red" Height="20" TextAlignment="Center"></TextBox>
<TextBox Text="1" Foreground="Red" Height="20" TextAlignment="Center"></TextBox>
  <TextBox Text="2" Foreground="Red" Height="20" TextAlignment="Center"></TextBox>
  <TextBox Text="3" Foreground="Red" Height="20" TextAlignment="Center"></TextBox>
  <TextBox Text="4" Foreground="Red" Height="20" TextAlignment="Center"></TextBox>
  <TextBox Text="5" Foreground="Red" Height="20" TextAlignment="Center"></TextBox>
  <TextBox Text="6" Foreground="Red" Height="20" TextAlignment="Center"></TextBox>
</ItemsControl>
</Grid>
</Window>

  执行上述代码我们会发现不会出现ScrollBar,我们定义了ItemsControl的高度为100,当下面的Item超过了这个高度后多出的部分直接被剪切掉了,通过查看Window.Resources中的模板,那么我们可以很好理解,因为ItemsControl的结构是一个Border里面嵌套了一个ItemsPresenter,根本么有ScrollViewer,所以当然不会出现ScrollBar。这个问题非常好解决,直接修改ItemsControl的模板,在Border里面加上一个ScrollViewer,问题解决。

 <Style x:Key="ItemsControlStyle1" TargetType="{x:Type ItemsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
<ScrollViewer>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

  效果如下所示:

下面来一步步深入,讨论一些复杂的问题。

在进行最终的问题解释之前,首先来探讨一下ItemsControl这个控件。

MSDN的解释是:表示用于呈现的项的集合的控件。

再看一下它的集成关系:

System.Object
  System.Windows.Threading.DispatcherObject
    System.Windows.DependencyObject
      System.Windows.Media.Visual
        System.Windows.UIElement
          System.Windows.FrameworkElement
            System.Windows.Controls.Control
              System.Windows.Controls.ItemsControl
                System.Windows.Controls.HeaderedItemsControl
                System.Windows.Controls.Primitives.DataGridCellsPresenter
                System.Windows.Controls.Primitives.DataGridColumnHeadersPresenter
                System.Windows.Controls.Primitives.MenuBase
                System.Windows.Controls.Primitives.Selector
                System.Windows.Controls.Primitives.StatusBar
                System.Windows.Controls.Ribbon.RibbonContextualTabGroupItemsControl
                System.Windows.Controls.Ribbon.RibbonControlGroup
                System.Windows.Controls.Ribbon.RibbonGallery
                System.Windows.Controls.Ribbon.RibbonQuickAccessToolBar
                System.Windows.Controls.Ribbon.RibbonTabHeaderItemsControl
                System.Windows.Controls.TreeView

通过这些继承关系,我们可以发现ItemsControl是很多包含Items的集合的控件的基类,比如ListBox还有TreeView等等。

关于ItemsControl中有几个非常重要的概念需要理解:

1 Template 这个不用说ItemsControl的模板,用于展现ItemsControl最终由什么构成,即外表呈现。

<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer x:Name="scrollViewer"
VerticalScrollBarVisibility="Auto"
Padding="5">
<ItemsPresenter ></ItemsPresenter>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>

  2 ItemsPanel属性,这个非常重要,这个是Items项的父容器,它决定了Items以何种方式去呈现,比如常用的Grid、 StackPanel、WrapPanel、UniformGrid、DockPanel等,甚至可以是自定义的Panel。

 <ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="Auto"
Height="Auto"
MaxWidth="500"
IsItemsHost="True"
HorizontalAlignment="Left"
VerticalAlignment="Center">
</WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

  3 ItemTemplate,这个属性表示每个Item将以何种方式呈现,有了这三种属性我们就可以定义我们需要的各种形式的界面。(下面的代码稍稍复杂一些)

<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,10,3"
HorizontalAlignment="Left"
VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Border Name="DutyPerson"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
Grid.ColumnSpan="2"
BorderBrush="#bdbdbd"
BorderThickness="1"
Padding="0"
Width="70"
Height="32"
ContextMenu="{StaticResource SetLeader}">
<StackPanel>
<TextBox x:Name="dutyPersonTextBox"
Text="{Binding DutyPersonName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
BorderThickness="0"
Height="30">
<TextBox.ToolTip>
<ToolTip HorizontalOffset="-18"
VerticalOffset="5"
BorderBrush="Transparent"
Background="Transparent"
HasDropShadow="False"
Placement="Top"
Visibility="{Binding IsLeader,Converter={StaticResource BoolToVisibility}}">
<Grid Margin="0">
<Image x:Name="personToolTipImage"
Stretch="Uniform"
RenderOptions.BitmapScalingMode="NearestNeighbor"
Width="88"
Height="36"
VerticalAlignment="Bottom"
Source="/AIPAnnouncement;component/ControlViews/Sources/Images/气泡.png">
</Image>
<TextBlock Text="领导"
FontSize="13"
HorizontalAlignment="Center"
VerticalAlignment="Center">
</TextBlock>
</Grid>
</ToolTip>
</TextBox.ToolTip>
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<interactive:ExInvokeCommandAction Command="{Binding DataContext.ModifyDutyPersonCommand,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=my:AnnouncementApp}}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TextBox}}">
</interactive:ExInvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="GotFocus">
<interactive:ExInvokeCommandAction Command="{Binding DataContext.TextBoxGotFocus,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=my:AnnouncementApp}}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TextBox}}">
</interactive:ExInvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
<Popup x:Name="popup"
PlacementTarget="{Binding ElementName=dutyPersonTextBox}"
Width="{Binding ActualWidth,ElementName=dutyPersonTextBox}"
IsOpen="{Binding ElementName=dutyPersonTextBox,Path=IsKeyboardFocused, Mode=OneWay}"
StaysOpen="True">
<Grid Background="Red">
<ListBox x:Name="lb_selecthistorymembers"
SnapsToDevicePixels="true"
ItemsSource="{Binding DataContext.SpecificHistoryMembers,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=my:AnnouncementApp},Mode=TwoWay}"
HorizontalAlignment="Stretch"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Background="#fff"
BorderThickness="1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<interactive:ExInvokeCommandAction Command="{Binding DataContext.OnSelectHistoryMembersListBoxSelected,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=my:AnnouncementApp},Mode=TwoWay}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}">
</interactive:ExInvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Bd"
Height="Auto"
Width="Auto"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled"
Value="false">
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="HorizontalAlignment" Value="Stretch"></Setter>
<Setter Property="VerticalAlignment" Value="Center"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Width="{Binding ActualWidth,ElementName=dutyPersonTextBox}"
>
</StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Name="Border"
BorderThickness="0">
<Grid Margin="2,1,1,1">
<Label x:Name="label"
Content="{Binding SpecificHistoryDutyPersonName}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
FontSize="13">
</Label>
</Grid>
</Border>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="Background"
Value="#00a3d9"
TargetName="Border">
</Setter>
<Setter Property="Background"
Value="#f8f3f0"
TargetName="label">
</Setter>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Popup>
</StackPanel>
</Border> <xui:Button x:Name="deleteAnnouncementItem"
Grid.Row="0"
Grid.Column="1"
Height="14"
Width="14"
Opacity="0"
HorizontalAlignment="Right"
VerticalAlignment="Top">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<interactive:ExInvokeCommandAction
Command="{Binding DataContext.DutyPersonDeleteCommand,RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=my:AnnouncementApp}}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=xui:Button}}">
</interactive:ExInvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
<Button.Background>
<ImageBrush ImageSource="/AIPAnnouncement;Component/ControlViews/Sources/Images/关闭.png">
</ImageBrush>
</Button.Background>
</xui:Button>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsLeader}"
Value="true">
<Setter Property="BorderBrush"
Value="#f00"
TargetName="DutyPerson">
</Setter>
</DataTrigger>
<Trigger Property="IsMouseOver"
Value="true"
SourceName="DutyPerson">
<Setter Property="BorderThickness"
Value="0"
TargetName="DutyPerson">
</Setter>
</Trigger>
<Trigger Property="IsMouseOver"
Value="true"
SourceName="deleteAnnouncementItem">
<Setter Property="Opacity"
Value="1"
TargetName="deleteAnnouncementItem">
</Setter>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>

  这里面的每一个Item定义成了类似于百度的搜索框一样的东西,当我们在文本输入框中输入文字时,会弹出一个Popup,里面是一个ListBox,我们可以从中挑选我们需要的选项,最后加入到TextBox中去,这里做了一个模板,在每一个TextBox下面添加一个Popup,当输入文字时会自动检索当前历史记录中是否存在当前项,这里面的核心是 IsOpen="{Binding  ElementName=dutyPersonTextBox,Path=IsKeyboardFocused,  Mode=OneWay}"  StaysOpen=”true” 这句的意思表示当前的Popup是否打开是取决于dutyPersonTextBox(一个TextBox控件)是否获得鼠标的焦点,这里使用IsKeyboardFocused来表示鼠标是否获取到焦点,后面我们会看一看具体效果的图片。

刚开始的时候,没有很多思考,当自己定义ItemsControl的ItemsPanel时,给它赋了一个定值,这里就埋下了一个很大的隐患,所以我们在不断的往ItemsControl中添加Item的项时,ItemsControl的高度只会维持在70,因为Items的容器ItemsPanel的高度就决定了ItemsControl的高度,当超过这个高度的时候会自动地去剪裁掉多余的部分,这是WPF的一个基本机理,所以我们在设置ItemsPanel的容器WrapPanel的时候一定要将Height设置为Auto,这样我们就能看到ItemsPanel的高度自动增加,这是其中一个方面,另外一个方面就是当我们必须设置ItemsPanel的高度或者是其父容器的高度为一个固定值假设为FixHeight,这样当随着Item的项的增多,ItemsPanel容器的高度超过FixHeight时,我们就会发现ScrollBar会出现,这些东西都是需要我们去不断地思考和总结的一些结论。     WPF的这种机理在很多的地方都是可以看到的,例如当我们往WrapPanel中添加项目时,为了保证能够使添加的项自动添加到第二行,那么我们必须为WrapPanel设置一个宽度,这样当我们添加项时才会自动跳转到下一行,因为如果我们不设置这个值,默认的高度和宽度都是Auto,这个在使用中必须要十分注意,并且平时多积累,才能真正地学以致用。

今天就总结这么多,最后看一看最终的效果,其中第三行人员这一行就是使用ItemsControl做出来的效果。

WPF中如何为ItemsControl添加ScrollViewer并显示ScrollBar的更多相关文章

  1. easyui中如何为validatebox添加事件(onblur、onclick等)

    在我们一般html的input标签,textbox事件可以直接使用onblur().onclick()事件,但是在easyui的validatebox没有onblur事件, 如果我们需要为valida ...

  2. idea中向pom.xml添加依赖时显示”not found dependency“

    总结: 起因:再输入hibernate-core的version时,开始写的是对的,就是 5.0.11.Final(这个也是跟着教程来的),直接就报错了,左等右等没用,也点过maven的reimpor ...

  3. WPF中添加Winform用户自定义控件

    过程:创建WPF工程->创建Winform用户自定义控件工程->WPF中引用控件->添加到Xaml页面 1.首先在WPF工程的解决方案上右击选择添加新建项目: 选择Windows窗体 ...

  4. 简述WPF中的画刷(Brush)

    原文:简述WPF中的画刷(Brush) -------------------------------------------------------------------------------- ...

  5. WPF中, 启用添加到RichTextBox中的控件

    原文:WPF中, 启用添加到RichTextBox中的控件   WPF中, 启用添加到RichTextBox中的控件                                           ...

  6. VS编程,WPF中两个滚动条 ScrollViewer 同步滚动的一种方法

    原文:VS编程,WPF中两个滚动条 ScrollViewer 同步滚动的一种方法 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/ar ...

  7. 在WPF中添加3D特性

    原文:在WPF中添加3D特性 35.4  在WPF中添加3D特性 本节介绍WPF中的3D特性,其中包含了开始使用该特性的信息. 提示: WPF中的3D特性在System.Windows.Media.M ...

  8. WPF中ItemsControl应用虚拟化时找到子元素的方法

    原文:WPF中ItemsControl应用虚拟化时找到子元素的方法  wpf的虚拟化技术会使UI的控件只初始化看的到的子元素, 而不是所有子元素都被初始化,这样会提高UI性能. 但是我们经常会遇到一个 ...

  9. WPF中TreeView控件数据绑定和后台动态添加数据(二)

    写在前面:在(一)中,介绍了TreeView控件MVVM模式下数据绑定的方法.在这篇文章中,将总结给节点添加事件的方法,这样说有些不对,总之实现的效果就是点击某个节点,将出现对应于该节点的页面或者数据 ...

随机推荐

  1. 复制数据库的Shell命令

    mysqldump -h$host db_old -uroot -p$pass | mysql -h$host db_new -uroot -p$pass 管道符号,是unix一个很强大的功能,符号为 ...

  2. SpringMVC @ResponseBody 406

    使用@ResponseBody注解可以让Controller返回json格式的数据,在需要传输一个对象信息的时候往往使用这种方式.如果在使用的时候遇到了406,一般原因是: 缺少jar包.转换成jso ...

  3. PHP HMAC_SHA1 算法 生成算法签名

    HMAC_SHA1(Hashed Message Authentication Code, Secure Hash Algorithm)是一种安全的基于加密hash函数和共享密钥的消息认证协议. 它可 ...

  4. OpenCV遍历彩色图像、灰度图像的像素值方法

    https://blog.csdn.net/mooneve/article/details/53001677 应用:将彩色图像转为灰度图像输出 方法一 使用ptr函数和指针 (高效) void mai ...

  5. 操作循环的关键字switch,break,return的应用及区别

    break 使用break结束循环  break可以终止循环 和 switch语句的运行; break用于结束一个循环,即跳出循环体,执行循环体之后的代码: switch 使用continue提前结束 ...

  6. 在DreamView中支持一辆新车

    Support a new Vehicle in DreamView In order to support a new vehicle in DreamView, please follow the ...

  7. python中numpy.pad简单填充0用法

    # -*- coding: utf-8 -*-"""Created on Sun Apr 28 22:07:02 2019 @author: jiangshan" ...

  8. Linux 下配置zookeeper集群

    我们首先准备三台服务器,IP地址分别如下(前提是要先安装JDK) 192.168.100.101 192.168.100.102 192.168.100.103 1.配置主机名到IP地址的映射(此步骤 ...

  9. keystone系列三:网关协议

    一 静态页面和动态页面 在了解了http协议后,我们知晓,一个web server的本质就是 浏览器发送一个HTTP请求: 服务器收到请求,生成一个HTML文档: 服务器把HTML文档作为HTTP响应 ...

  10. c# 打印 主板信息CPU信息

    Win32_Processor CPU 参数说明: AddressWidth --在32位操作系统,该值是32,在64位操作系统是64.Architecture --所使用的平台的处理器架构.Asse ...