TreeView vs Accordion vs DataGrid。





5.00/5 (2投票s)
在 Silverlight 中导航数据时,Accordion 与 TreeView 和 DataGrid 的比较。
在 Silverlight 中导航数据时,Accordion 与 TreeView 和 DataGrid 的比较。
动机
如果要使用 Silverlight 功能,我们需要对 Silverlight SDK 有很好的了解。本文的主要任务是仔细研究三种控件比较背景下的一些技术:
TREEVIEW vs ACCORDION vs DATAGRID。

而这一切都始于:

在找工作时,我偶然发现了一个任务,要求创建一个如上图所示的外观。我将如何在本文中展示它。


此外,我们将查看一些对象,其中大部分是在 SDK v. December 2011 中添加的,将包括:
- TREEVIEW
- TREEVIEWITEM
- ACCORDION
- ACCORDIONITEM
- DATAGRID
- CHART
- SERIES
- SERIESDATAPOIND
- WRAPPANEL
- CONTEXTMENU
此外还有:
- 如何动态更改 FontFamily 和 FontSize(两种技术)。
- 如何存储用户自己的设置(简化)。
- 如何设置可视化控件的样式:CheckBox、RadioButtom、DataGrid。

要求
- 了解如何在 Visual Studio C# 中创建新的 Silverlight 项目。
- Xaml 基础知识库。
- Silverlight 或 WPF 基础知识。
- 此外,还安装了 Silverlight SDK 5 版,时间是 2011 年 12 月。
工作原理
截屏显示了应用程序窗口的功能分解。

- 导航数据
- Accordion
- Treeview
- DataGata
- 主数据输入节点表单
- 图表数据
- 设置
- 颜色设置
- 设置字体
- 设置字体大小
- 待实现
- 待实现
- 子窗口,用于输入依赖于主数据并分配给特定节点的数据。
引言
Ad.1a. Accordion 控件是许多类型的 Expander 控件的列表。它作为 AccordionItem 实现。AccorionItem HeaderedContentControl 是一个开发,包含标题和内容。
在这个主题中,我使用了 AccordionItem 及其标题来呈现根节点名称并演示其分配的颜色,以及更改颜色的能力,这反映在该节点上呈现的数据中。标题中的另一个箭头图标用于展开,作为眼睛图标 (CheckBox) 在选择节点时被锐化。旁边是内容中呈现的数据标题。
接下来是彩色方块图标和上下文吸管 (RadioButton),允许更改颜色。当吸管图标点亮(通过单击它)时,您可以从窗口 4a 中选择颜色,右键单击任意位置会减慢此功能。
Ad. 1b. 操作类似于 1.a。但是,在本讨论中,我使用了 TreeView 控件。
TreeView 控件及其实现
实现 TreeView 的头文件添加了对命名空间的引用:
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
控件本身是一个声明:
<controls:TreeView x:Name="navigateTreeView" ItemsSource="{StaticResource listEmployee}" ItemTemplate="{StaticResource employeeEntry}"/>
我们有三个属性——第一个是我们将在 XAML(大多数使用 {Binding ElementName = nameTargetControl, Path = PrapertyTargetControl})和 IL (C# 或 VB) 中引用的名称,第二个是数据源,其后是元素模式,依次是次级显示面板。
TreeView 控件中的数据源是层次化的,即每个级别都必须为其下属提供源节点。每个节点都有自己的显示模式,可以提供或使用默认模式,而无需处理它。但是,我们在这里会有点麻烦,因为我们希望使用自己的模型来提供标题和元素。我们通过 HierarchicalContentControl 控件来做到这一点,该控件将特定节点封装起来,用于数据以及调整样式和功能。我们示例中的主要级别如下所示:
让我们找到代码行 <!-- HierarchicalDataTemplates Level One-->
<Grid x:Name="LayoutRoot" Background="White"> … <Grid> <Grid.Resources> <Style TargetType="RadioButton"> … </Style> <Style TargetType="CheckBox"> … </Style> <Style TargetType="layoutToolkit:AccordionItem"> … </Style> <!-- HierarchicalDataTemplates Level Two--> <common:HierarchicalDataTemplate x:Key="timeWorksEntry"> <StackPanel Orientation="Horizontal"> <ContentPresenter Margin="0 0 4 0" Content="{Binding Icon}" /> <TextBlock Text="{Binding DateWork, FallbackValue=test_DayWork, StringFormat='{}{0:dd.MM.yyyy}'}" /> <TextBlock Text="{Binding AnyText, FallbackValue=': From '}" /> <TextBlock Text="{Binding Path=StartWork, FallbackValue=test_StartWork, StringFormat='{}{0:HH:mm}'}" /> <TextBlock Text="{Binding AnyText, FallbackValue=' to '}" /> <TextBlock Text="{Binding EndWork, FallbackValue=test_EndWork, StringFormat='{}{0:HH:mm}'}"> </TextBlock> </StackPanel> </common:HierarchicalDataTemplate> <!-- HierarchicalDataTemplates Level One--> <common:HierarchicalDataTemplate x:Key="employeeEntry" ItemsSource="{Binding Path=TimeWorks}" ItemTemplate="{StaticResource timeWorksEntry}"> <StackPanel Orientation="Horizontal"> <controlsInputToolkit:ContextMenuService.ContextMenu> <controlsInputToolkit:ContextMenu> <controlsInputToolkit:MenuItem Header="Add Node" Click="MenuItem_Add"></controlsInputToolkit:MenuItem> <controlsInputToolkit:MenuItem Header="Add SubNode" Click="MenuItem_AddSubNode"></controlsInputToolkit:MenuItem> <controlsInputToolkit:MenuItem Header="Remove Node" Click="MenuItem_Del"></controlsInputToolkit:MenuItem> </controlsInputToolkit:ContextMenu> </controlsInputToolkit:ContextMenuService.ContextMenu> <Grid Cursor="Hand"> <Grid.ColumnDefinitions> <ColumnDefinition Width="150" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <CheckBox FontFamily="{Binding Source={StaticResource userSetting},Path=FontLabel}" FontSize="{Binding Source={StaticResource userSetting},Path=FontSize}" Cursor="Hand" VerticalAlignment="Center" Margin="3,0,2,0" IsChecked="{Binding RelativeSource={RelativeSource AncestorType=controls:TreeViewItem,AncestorLevel=1},Path=IsExpanded,Mode=TwoWay}" Content="{Binding Name, FallbackValue='Main Name'}"></CheckBox> <RadioButton x:Name="pipetaCB" Grid.Column="2" Cursor="Hand" Checked="RadioButton_Checked_1" Tag="{Binding}" GroupName="pipete" Margin="3,0,2,0"> <RadioButton.Content> <Image Height="16" Width="16" Opacity="{Binding RelativeSource={RelativeSource AncestorType=RadioButton, AncestorLevel=1},Path=IsChecked,Converter={StaticResource tToO}}" Source="pipete.png" /> </RadioButton.Content> </RadioButton> <Border BorderBrush="Black" BorderThickness="1" Padding="1" Grid.Column="1" Width="60" x:Name="pipetaBorder" Margin="0,0,0,2"> <Rectangle x:Name="pipetaRec"> <Rectangle.Fill> <SolidColorBrush Color="{Binding Color}" /> </Rectangle.Fill> </Rectangle> </Border> <Button Margin="3,0,2,0" Grid.Column="3" Width="16" Click="MenuItem_AddSubNode" IsEnabled="{Binding RelativeSource={RelativeSource AncestorType=controls:TreeViewItem,AncestorLevel=1},Path=IsSelected,Mode=TwoWay}" Content="+"></Button> <Button Margin="2,0,2,0" Content="-" Grid.Column="4" Width="16"> </Button> <ContentPresenter /> </Grid> </StackPanel> </common:HierarchicalDataTemplate> </Grid.Resources>
位于第一层之下的所有内容都是我们控件的样式,最后是下一个节点。该图直观地显示了这一点。

值得注意的是,功能的描述和它们满足匹配外观的多功能性。复选框控制的眼睛用于镜像展开器及其内容的指示到节点的描述。例如,它可以用于图中所示的节点。图形可以包括或不包括通道或级别控件等。CheckBox 控件的一个非常重要的特性是具有 Command 和 CommandParametr 属性,这将使其在视图模式中尽可能地不依赖于数据(MVP、MVVM、MVC 等)。在他的示例中,但我使用了对父容器 (TreeViewItem) 及其 IsExpanded 的简单引用,这正如我所提到的,它的行为是双重的。
IsChecked="{Binding RelativeSource={RelativeSource AncestorType=controls:TreeViewItem,AncestorLevel=1},Path=IsExpanded,Mode=TwoWay}" Content="{Binding Name, FallbackValue='Main Name'}"
内容与提供的数据源及其路径名称相关联,选项 FallbackValue = "Main Name" 意味着如果绑定提供 null 值或任何内容,它将显示此属性所具有的内容。值得注意的是,FallbackValue 您也可以使用绑定 FallbackValue = "{Binding ... 但必须考虑到,如果绑定属性出错,Silverlight 引擎不会忽略此错误并导致应用程序崩溃。我建议在绑定 FallbackValue 时要格外小心。WPF 中也有类似的情况,但那里存在:
<PriorityBinding> Bindings </PriorityBinding>
不幸的是,Silverlight 中缺少这一点。特别是 Async,这在 WebServices 中很常见。矩形边框包含分配给数据节点的颜色的可视化。在此实现中,颜色更改是通过将吸管移到图标上(风格化的 RadioButton)并单击,以及如何点亮它来指示屏幕另一部分中 SetColor 中包含的调色板来完成的。RadioButton 控件已剥夺了部分演示(RadioIcon),并且图像已放置在内容属性中。此控件已处理事件。
Checked="RadioButton_Checked_1"
C# 后端代码
private void RadioButton_Checked_1(object sender, RoutedEventArgs e) { fe = sender as FrameworkElement; this.setColor.SelectionChanged += setColor_SelectionChanged; this.MouseRightButtonDown += MyProposition_MouseRightButtonDown; } void MyProposition_MouseRightButtonDown(object sender, MouseButtonEventArgs e) { ToggleButton rb = fe as ToggleButton; if (rb != null) rb.IsChecked = false; this.setColor.SelectionChanged -= setColor_SelectionChanged; this.MouseRightButtonDown -= MyProposition_MouseRightButtonDown; } void setColor_SelectionChanged(object sender, SelectionChangedEventArgs e) { Shape selectObj = (Shape)e.AddedItems[0]; SolidColorBrush color = selectObj.Fill as SolidColorBrush; (fe.Tag as Employee).Color = color.Color; this.Cursor = Cursors.Arrow; }
为了传递颜色,我使用了 Tag 属性,这不是很优雅但有效且功能性测试,甚至在需要控制传递值时也是如此。Silverlight 中添加的一个有趣功能是自由使用 ContextMenu。我添加了处理节点上下文菜单,其中包含三个项目:

- 添加节点,将光标转发到表单,添加根节点。
- 添加子节点,在当前节点中启动新条目并打开一个弹出窗口,显示数据并等待确认将这些数据添加到节点。
- 删除节点 - 删除光标所在的节点。
#region treeViewContextMenu private void MenuItem_Del(object sender, RoutedEventArgs e) { Employee employee = ((FrameworkElement)sender).DataContext as Employee; if (null != employee) { _employees.Remove(employee); } } private void MenuItem_AddSubNode(object sender, RoutedEventArgs e) { Employee contextEmployee = (Employee)((FrameworkElement)sender).DataContext; bool resultDialog = false; this.twEmployee_ChildWindow = new TimeWorkEmployeeChildWindow(); // Default data TimeWork newTimeWork = new TimeWork(); newTimeWork.DateWork = DateTime.Now; newTimeWork.StartWork = DateTime.Parse("9:15"); newTimeWork.EndWork = DateTime.Parse("17:15"); //twEmployee_ChildWindow.Closed += new EventHandler(twEmployee_ChildWindow_Closed); twEmployee_ChildWindow.Closed += (s, arg) => { resultDialog = (bool)twEmployee_ChildWindow.DialogResult; if (resultDialog) { // Add to parent contextEmployee.TimeWorks.Add(newTimeWork); } }; // Data for ChildWindow this.twEmployee_ChildWindow.DataContext = newTimeWork; this.twEmployee_ChildWindow.Title = contextEmployee.Name; // Show window this.twEmployee_ChildWindow.Show(); } //private void twEmployee_ChildWindow_Closed(object sender, EventArgs e) //{ // bool resultDialog = (bool)twEmployee_ChildWindow.DialogResult; //} private void MenuItem_Add(object sender, RoutedEventArgs e) { this.navigateDataForms.Focus(); } #endregion
下图显示了:
<!-- HierarchicalDataTemplates Level Two-->

Accordion 及其实现
如前所述,Control 类型是一组 HeaderContentControl 控件,其实现与 Expander 控件列表非常相似。Accordion 控件整合并优化了某个功能。
Accordion 的声明
<layoutToolkit:Accordion x:Name="navigatorAccordion" SelectionMode="ZeroOrOne" ItemsSource="{StaticResource listEmployee}"/>
不要忘记对 SDK 库的项目引用。Xaml 文件头中我们需要放置对库的引用。
xmlns:layoutToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
ItemsSource="{StaticResource listEmployee}"
是控件的名称,它将引用 C# 代码中的控件。
ItemsSource="{StaticResource listEmployee}"
是数据源控件。各个元素根据层次结构节点及其组件的结构显示,但单个级别从属关系的基本实现意味着在某个作业中可以更改,甚至某些场景也允许这种梦想。根节点的标题,包括可视化和功能,与 TreeView 的标题非常相似,毕竟这就是计划。与 TreeView 不同的是,整个内容都采用一种样式。
<Style TargetType="layoutToolkit:AccordionItem"> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <ListBox ItemsSource="{Binding TimeWorks }" HorizontalAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch"> <Rectangle Margin="15,0,5,0" Width="6" Height="6" Stroke="Black" /> <TextBlock Text="{Binding StartWork, FallbackValue=test}" /> <TextBlock Text="{Binding YouText, FallbackValue=' to '}" /> <TextBlock Text="{Binding EndWork, FallbackValue=test}" /> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </DataTemplate> </Setter.Value> </Setter> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="HeaderTemplate"> <Setter.Value> <DataTemplate> <Grid Cursor="Hand"> <controlsInputToolkit:ContextMenuService.ContextMenu> <controlsInputToolkit:ContextMenu> <controlsInputToolkit:MenuItem Header="Add Node" Click="MenuItem_Add" /> <controlsInputToolkit:MenuItem Header="Add SubNode" Click="MenuItem_AddSubNode" /> <controlsInputToolkit:MenuItem Header="Remove Node" Click="MenuItem_Del" /> </controlsInputToolkit:ContextMenu> </controlsInputToolkit:ContextMenuService.ContextMenu> <Grid.ColumnDefinitions> <ColumnDefinition Width="150" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <CheckBox Cursor="Hand" VerticalAlignment="Center" Margin="2,0,2,0" IsChecked="{Binding RelativeSource={RelativeSource AncestorType=layoutToolkit:AccordionItem,AncestorLevel=1},Path=IsSelected,Mode=TwoWay}" Content="{Binding Name, FallbackValue='Tytuł Imię i nazwisko'}"></CheckBox> <RadioButton x:Name="pipetaCB" Grid.Column="2" Cursor="Hand" Checked="RadioButton_Checked_1" Tag="{Binding}" GroupName="pipete" Margin="2,0,2,0"> <RadioButton.Content> <Image Height="12" Width="12" Opacity="{Binding RelativeSource={RelativeSource AncestorType=RadioButton, AncestorLevel=1},Path=IsChecked,Converter={StaticResource tToO}}" Source="pipete.png" /> </RadioButton.Content> </RadioButton> <Button Margin="3,0,2,0" Grid.Column="3" Width="16" Click="MenuItem_AddSubNode" IsEnabled="{Binding RelativeSource={RelativeSource AncestorType=layoutToolkit:AccordionItem,AncestorLevel=1},Path=IsSelected,Mode=TwoWay}" Content="+"></Button> <Button Margin="2,0,2,0" Content="-" Grid.Column="4" Width="16"> </Button> <Border BorderBrush="Black" BorderThickness="1" Padding="1" Grid.Column="1" Width="60" x:Name="pipetaBorder" Margin="0,0,0,2"> <Rectangle x:Name="pipetaRec"> <Rectangle.Fill> <SolidColorBrush Color="{Binding Color}" /> </Rectangle.Fill> </Rectangle> </Border> </Grid> </DataTemplate> </Setter.Value> </Setter> </Style>
一些 ContentTemplate 可能需要最少的评论。它作为 ListBox 控件的内容包含在其中,该控件在其容器中显示与从属根节点关联的项。需要更多关注标题,但这基本上是 TreeView 中使用的标题的反映,同时保持了功能。支持相同的事件。
DataGrid 及其实现
命名空间
xmlns:datagrid="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
声明
<datagrid:DataGrid x:Name="navigateDataGrid" AutoGenerateColumns="False" ItemsSource="{StaticResource listEmployee}"/>
我用于标识控件名称的声明属性:
AutoGenerateColumns="False"
我将其设置为 false,表示我希望提供相同的列模式。接下来是数据源。我在数据源处稍作停顿,因为我对所有操作系统提供的时效数据控件都使用了相同的语法。在此视图中,在 UserControl.Resource 中声明并创建了 Xaml 声明中命名的对象。
<local:ListEmployee x:Key="listEmployee" />
提供程序类包含在 ListEmployee ListEmployee.cs 文件中。此声明实际上仅在解决方案设计阶段扮演数据提供者的角色。但没有任何阻碍它成为目标数据源,但是,在数据同步方面会出现一些困难。我将动态数据源用作在 IL 代码 (C# 或 VB) 后台进行的赋值。具体来说,是 Loaded 事件处理类视图。
void MyProposition_Loaded(object sender, RoutedEventArgs e) { GenerateColorForSetColor(); this.navigatorAccordion.ItemsSource = _employees; this.navigateTreeView.ItemsSource = _employees; this.navigateDataGrid.ItemsSource = _employees; this.navigateDataForms.ItemsSource = _employees; this.myChart.DataContext = _employees; }
直接添加到控件的列模式:
<datagrid:DataGrid x:Name="navigateDataGrid" AutoGenerateColumns="False" ItemsSource="{StaticResource listEmployee}"> <datagrid:DataGrid.Columns> <datagrid:DataGridTemplateColumn Header="Color"> <datagrid:DataGridTemplateColumn.CellTemplate> <DataTemplate> <Border BorderBrush="Black" BorderThickness="1" Padding="2" CornerRadius="2"> <Rectangle MouseLeftButtonDown="Rectangle_MouseLeftButtonDown"> <Rectangle.Fill> <SolidColorBrush Color="{Binding Color}" /> </Rectangle.Fill> </Rectangle> <controlsInputToolkit:ContextMenuService.ContextMenu> <controlsInputToolkit:ContextMenu> <controlsInputToolkit:MenuItem Header="Add Node" Click="MenuItem_Add"></controlsInputToolkit:MenuItem> <controlsInputToolkit:MenuItem Header="Add SubNode" Click="MenuItem_AddSubNode"></controlsInputToolkit:MenuItem> <controlsInputToolkit:MenuItem Header="Remove Node" Click="MenuItem_Del"></controlsInputToolkit:MenuItem> </controlsInputToolkit:ContextMenu> </controlsInputToolkit:ContextMenuService.ContextMenu> </Border> </DataTemplate> </datagrid:DataGridTemplateColumn.CellTemplate> </datagrid:DataGridTemplateColumn> <datagrid:DataGridTextColumn Header="Id" Binding="{Binding Id}" /> <datagrid:DataGridTextColumn Header="Name" Binding="{Binding Name}" /> <datagrid:DataGridTextColumn Header="Summary" Binding="{Binding Summary, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" /> <datagrid:DataGridTemplateColumn> <datagrid:DataGridTemplateColumn.CellTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Button Content="+" Margin="5,0,2,0" Width="16" Click="MenuItem_AddSubNode" /> </StackPanel> </DataTemplate> </datagrid:DataGridTemplateColumn.CellTemplate> </datagrid:DataGridTemplateColumn> </datagrid:DataGrid.Columns>
第一列包含熟悉但更改了颜色的功能,以定义节点的功能。在这种情况下,直接单击正方形并包含一种颜色,然后强制选择一种新颜色。单击功能之外的任何点都会取消导航控件。最后一列添加了一个按钮,用于开始向选定节点添加新的从属元素。其他元素不需要太多关注。目标节点也由 DataGrid 控件指示,该控件连接到在导航控件中提供选定节点的数据源。
<datagrid:DataGrid x:Name="subDataGrid" ItemsSource="{Binding ElementName=navigateDataGrid, Path=SelectedItem.TimeWorks}">
只需指出元素的名称和控件中的具体路径。
总结对比
在这个应用程序中,在我看来,最好使用 Accordion。当我们只使用单个级别的分层数据时。
TreeView 控件同样具有吸引力,但似乎它的命运更适合深度未知或已知元素但更方便以这种形式传递的树形结构。
在上面的示例中,DataGrid 表现最差,并不是因为其不足。DataGrid 在需要大量以逻辑级别呈现的项目结构中提供了出色的服务。无论是 TreeView 还是 Accordion 都无法完全满足场景需求,尽管一切都在我们面前。
此外
此比较的其他方面是使用 Chart、Series 和 SeriesDataPoint,以及 WrapPanel、ChildWindow、DataForm 和 DataField 以及其他一些控件。
Chart 控件是一个数据图形表示容器,可以包含一个或多个此类系列类(PieSeries、ColumnSeries、BarSeries 等)。Series 是数据的具体可视化。
在我的文章中,我使用了 ColumnSeries,通过在 Series 集合中声明它来添加到图表控件中。
<chartingToolkit:Chart Grid.Row="4" Title="Works time" x:Name="myChart" DataContext="{StaticResource listEmployee}" Palette="{StaticResource GrowDataPointPalette}" Style="{StaticResource ChartStyle}"> <chartingToolkit:Chart.Series> <chartingToolkit:ColumnSeries x:Name="presentationData" LegendItemStyle="{StaticResource LegendItemStyle}" ItemsSource="{Binding}" DependentValueBinding="{Binding Summary}" > <chartingToolkit:ColumnSeries.DataPointStyle> <Style TargetType="chartingToolkit:ColumnDataPoint"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="chartingToolkit:ColumnDataPoint"> <Grid x:Name="Root" Opacity="1"> <ToolTipService.ToolTip> <StackPanel Margin="2,2,2,2"> <ContentControl Content="{TemplateBinding DependentValue}" /> </StackPanel> </ToolTipService.ToolTip> <Rectangle StrokeThickness="{TemplateBinding BorderThickness}" Stroke="{TemplateBinding BorderBrush}"> <Rectangle.Fill> <SolidColorBrush Color="{Binding Color}" /> </Rectangle.Fill> </Rectangle> <TextBlock HorizontalAlignment="Center" Text="{Binding Name}" FontFamily="{Binding Source={StaticResource userSetting},Path=FontLabel}" FontSize="11" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </chartingToolkit:ColumnSeries.DataPointStyle> </chartingToolkit:ColumnSeries> </chartingToolkit:Chart.Series> </chartingToolkit:Chart>
摘要
此外,在上述两种技术中,我使用了更改字体大小等设置。在构造 1.a. (Accordion) 中,我使用了直接绑定技术(绑定 NameElement),这会自动涉及更改,我们需要使用其他技术来读取设置以保留它们。
第二种技术是在 UserSetting 类中使用中介,直接在 Xaml 中记录其字段的初始化。从控件 3.b、4.b、3.c 更改的任何设置都会写入对象,并由选定项目上的订阅者接收。显然,通过这种中介等附加服务使用、记录和更新非常简单。
此致,Andrzej Skutnik。
解释
2012 年 7 月 6 日
我的项目中无意中留下了一些“无用”的代码。现在,在您的区域中保留了 My_Proposition.xaml.cs。
#region treeView void navigateTreeView_Unloaded(object sender, RoutedEventArgs e) { TreeView v = sender as TreeView; v.SelectedItemChanged -= v_SelectedItemChanged; v.MouseRightButtonDown += (senderMRBU, argMBRD) => { argMBRD.Handled = false; }; } void navigateTreeView_Loaded(object sender, RoutedEventArgs e) { // Tą technikę stosuje kiedy znam głębokość hierarchii TreeView v = sender as TreeView; // Ukryjmy to przed użytkownikiem v.Opacity = 0; v.SelectedItemChanged += v_SelectedItemChanged; v.MouseRightButtonDown += (senderMRBU, argMBRD) => { argMBRD.Handled = true; }; IEnumerable<object> items = v.Items; if (items != null) { v.ApplyTemplate(); v.UpdateLayout(); foreach (var d in items) { TreeViewItem item = v.ItemContainerGenerator.ContainerFromItem(d) as TreeViewItem; item.Selected += item_Selected; item.Expanded += item_Expanded; if (item.Items.Count > 0) { OnSelected_Expanded(item); } } } v.Opacity = 1; } private static void OnSelected_Expanded(ItemsControl item) { item.SetValue(TreeViewItem.IsExpandedProperty, true); item.ApplyTemplate(); item.UpdateLayout(); foreach (var d1 in item.Items) { // Oczywiście można to usystematyzować TreeViewItem itemChild = item.ItemContainerGenerator.ContainerFromItem(d1) as TreeViewItem; itemChild.Selected += (s, e_arg) => { }; item.SetValue(TreeViewItem.IsExpandedProperty, false); } } void item_Expanded(object sender, RoutedEventArgs e) { } void item_Selected(object sender, RoutedEventArgs e) { } void v_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) { } #endregion
但是,如果在项目中发现自己,我应该解释为什么以及它们的目的是什么。方法:
void navigateTreeView_Loaded(object sender, RoutedEventArgs e) {…}
Loaded 事件处理程序是 TreeView 控件,在加载类时发生。在方法体中依次执行任务:
- 对用户隐藏操作——尽管在此阶段它仍然不可见,但当我们想要重构运行应用程序的功能时,值得记住。
- 我建立元素中的事件处理更改并放弃对鼠标右键的支持。
- …
- 恢复控件的可见性。
这就是我们需要保持功能所需的一切。此方法的其余部分只执行一次,用于测试我构建 TreeView 树结构的正确性。它标识特定的容器及其元素或分配 TreeViewItem Selected 事件处理程序。我们知道,树中的每个对象都封装在 TreeViewItem 类中。整个层次结构都是如此。因此,如果您订阅事件,特定实例的 DataContext 由用户指定与容器关联的特定数据对象。在我们的示例中,分别是 TimeWork 和 Employee。当添加处理控件事件覆盖父级和新数据源时,此方法部分的所有活动都已取消。如果我们放弃覆盖:
void MyProposition_Loaded(object sender, RoutedEventArgs e) { GenerateColorForSetColor(); //this.navigatorAccordion.ItemsSource = _employees; //this.navigateTreeView.ItemsSource = _employees; //this.navigateDataGrid.ItemsSource = _employees; //this.navigateDataForms.ItemsSource = _employees; //this.myChart.DataContext = _employees; };
数据源的 Selected 事件
void item_Selected(object sender, RoutedEventArgs e) { }
当单击时,各个元素(例如 TreeViewItem 控件)将被处理。请记住,在此方法通过后,当您初始化控件时添加的新项将不被尊重。因此不会响应选择。在这里,如果我们接受这种策略,我们必须自己处理。同样,这适用于 Expanded 事件。目前,对这些事件的支持除了存在之外什么都不做。
抱歉给您带来不便。