ItemsControl基本概念


用法1:设置奇偶行不同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <ItemsControl AlternationCount="2" ItemsSource="{Binding Stars}"> <ItemsControl.Template> <ControlTemplate TargetType="ItemsControl"> <DockPanel> <TextBlock DockPanel.Dock="Top" Text="Header" /> <ItemsPresenter /> </DockPanel> </ControlTemplate> </ItemsControl.Template> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Border x:Name="border"> <TextBlock Margin="10" Text="{Binding}" /> </Border> <DataTemplate.Triggers> <Trigger Property="ItemsControl.AlternationIndex" Value="1"> <Setter TargetName="border" Property="Background" Value="#ccc" /> </Trigger> </DataTemplate.Triggers> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
|
1 2 3 4 5
|
public ObservableCollection<string> Stars { get; } = new() { "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune" };
|

用法2:展示几何
1 2 3 4 5 6 7 8 9 10 11
|
public ObservableCollection<Shape> Shapes { get; } = new() { new(0, new(50, 50), Brushes.Red), new(1, new Point(150, 70), Brushes.Green), new(1, new Point(300, 160), Brushes.Blue), new(0, new Point(240, 260), Brushes.Yellow), };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <ItemsControl ItemsSource="{Binding Shapes}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Canvas /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemContainerStyle> <Style TargetType="ContentPresenter"> <Setter Property="Canvas.Left" Value="{Binding Pos.X}" /> <Setter Property="Canvas.Top" Value="{Binding Pos.Y}" /> </Style> </ItemsControl.ItemContainerStyle> <ItemsControl.ItemTemplate> <DataTemplate> <Rectangle Name="rect" Width="40" Height="40" Fill="{Binding Color}" /> <DataTemplate.Triggers> <DataTrigger Binding="{Binding Type}" Value="1"> <Setter TargetName="rect" Property="RadiusX" Value="20" /> <Setter TargetName="rect" Property="RadiusY" Value="20" /> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
|

用法3:不同数据类型展示
定义数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public abstract class Fruit { public int Amount { get; set; } public string FruitType => this.GetType().Name; } public class Apple : Fruit { } public class Banana : Fruit { }
public ObservableCollection<Fruit> Fruits { get; } = new() { new Apple { Amount = 3 }, new Apple { Amount = 2 }, new Banana { Amount = 6 }, new Apple { Amount = 4 }, new Banana { Amount = 1 }, new Banana { Amount = 5 }, };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <ItemsControl ItemsSource="{Binding Fruits}"> <ItemsControl.Resources> <DataTemplate DataType="{x:Type local:Apple}"> <Border Height="30" Background="Aquamarine"> <StackPanel VerticalAlignment="Center" Orientation="Horizontal"> <TextBlock Width="80" Text="{Binding FruitType}" /> </StackPanel> </Border> </DataTemplate> <DataTemplate DataType="{x:Type local:Banana}"> <Border Height="30" Background="LightPink"> <StackPanel VerticalAlignment="Center" Orientation="Horizontal"> <TextBlock Width="80" Text="{Binding FruitType}" /> </StackPanel> </Border> </DataTemplate> </ItemsControl.Resources> </ItemsControl>
|

用法4,相同类型不同属性使用不同模板
定义数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public record Employee(string Name, Gender Gender, int Age);
public enum Gender { Male, Female };
public ObservableCollection<Employee> Employees { get; } = new() { new("John", Gender.Male, 27), new("Anna", Gender.Female, 31), new("Joyce", Gender.Female, 28), new("Tony", Gender.Male, 40), new("Brian", Gender.Male, 36) };
|
要根据Gender性别属性显示不同的背景色,要使用ItemTemplateSelector。
ItemTemplateSelector
定义ItemTemplateSelector
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class EmployeeTemplateSelector : DataTemplateSelector { public DataTemplate MaleTemplate { get; set; } public DataTemplate FemaleTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container) { var element = container as FrameworkElement; var employee = item as Employee; return employee!.Gender switch { Gender.Male => MaleTemplate, Gender.Female => FemaleTemplate, _ => throw new ArgumentException() }; } }
|
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <ItemsControl FontSize="18" ItemsSource="{Binding Employees}"> <ItemsControl.ItemTemplateSelector> <local:EmployeeTemplateSelector> <local:EmployeeTemplateSelector.MaleTemplate> <DataTemplate> <StackPanel Background="LightCyan" Orientation="Horizontal"> <TextBlock Width="80" Text="{Binding Name}" /> <TextBlock Width="80" Text="{Binding Gender}" /> <TextBlock Text="{Binding Age}" /> </StackPanel> </DataTemplate> </local:EmployeeTemplateSelector.MaleTemplate> <local:EmployeeTemplateSelector.FemaleTemplate> <DataTemplate> <StackPanel Background="LightPink" Orientation="Horizontal"> <TextBlock Width="80" Text="{Binding Name}" /> <TextBlock Width="80" Text="{Binding Gender}" /> </StackPanel> </DataTemplate> </local:EmployeeTemplateSelector.FemaleTemplate> </local:EmployeeTemplateSelector> </ItemsControl.ItemTemplateSelector> </ItemsControl>
|

ItemsControl和ListBox的区别
和ListBox不同的是,ItemsControl默认不启用UI虚拟化,在呈现数据量较大的时候会导致严重的性能问题。因此如果数据量较大,最好为其开启虚拟化,具体需要做的是:
1:(必需)将其ItemsPanel设置为虚拟化容器,如VirtualizingStackPanel。
2:(必需)重写ControlTemplate,为其添加ScrollViewer并将其的CanContentScroll属性设置为True。注意,用ScrollViewer包裹ItemsControl是无效的。
3:(非必需,进一步优化)在ItemsControl上设置附加属性VirtualizingPanel.VirtualizationMode为Recycling,以此进一步减少内存分配和回收压力
