WPF新教程(补充2)

ListBox集合控件

  • 作用: 包裹一个个子项供用户选择(展示一条数据)
  • 实例: 当用户选中哪个子项时,文本框控件就展示该子项内容
......
<StackPanel Margin="20" Width="300">
    <TextBox x:Name="MyTxtBox" Height="40" VerticalAlignment="Center" />
    <ListBox x:Name="MyListBox" Height="120" SelectionChanged="MyListBox_SelectionChanged" >
        <ListBoxItem Content="Item1" />
        <ListBoxItem>Item2</ListBoxItem>
        <ListBoxItem Content="Item3" />
        <ListBoxItem Content="Item4" />
        <ListBoxItem Content="Item5" />
        <ListBoxItem Content="Item6" />
        <ListBoxItem Content="Item7" />
        <ListBoxItem Content="Item8" />
        <ListBoxItem Content="Item9" />
    </ListBox>
</StackPanel>

// cs

namespace GatherControlDemo
{

    public partial class ListBoxDemo : Window
    {
        public ListBoxDemo()
        {
            InitializeComponent();
        }

        private void MyListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var selectItem = MyListBox.SelectedItem as ListBoxItem;
            MyTxtBox.Text = selectItem.Content.ToString();
        }
    }
}

ListView列表展示控件

  • 作用: 展示多个对象的多条数据
<Window x:Class="GatherControlDemo.ListViewDemo"
      ......
        Title="ListViewDemo" Height="450" Width="800">
    <Grid Margin="10">
        <ListView x:Name="studentListView">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="姓名" Width="120" DisplayMemberBinding="{Binding Name}"  />
                    <GridViewColumn Header="年龄" Width="120" DisplayMemberBinding="{Binding Age}" />
                    <GridViewColumn Header="分数" Width="120" DisplayMemberBinding="{Binding Score}" />
                    <!--<GridViewColumn Header="是否通过" Width="100" >
                       
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox IsChecked="{Binding IsPassed}" IsEnabled="False"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>-->
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

// 新建 student.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GatherControlDemo
{
    class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public double Score { get; set; }
        //public bool IsPassed => Score >= 60;
    }
}

// main.cs
......
namespace GatherControlDemo
{
 
    public partial class ListViewDemo : Window
    {
        public ListViewDemo()
        {
            InitializeComponent();
            LoadStudentData();
        }

        private void LoadStudentData()
        {
            var students = new List<Student> {
                new Student { Name = "张三", Age = 20, Score = 85.5 },
                new Student { Name = "李四", Age = 22, Score = 59.0 },
                new Student { Name = "王五", Age = 21, Score = 72.5 },
                new Student { Name = "赵六", Age = 19, Score = 91.0 }
            };

            studentListView.ItemsSource = students;
        }
    }
}

DataGrid表格控件

  • 作用: 多功能的数据表格(含编辑)
- ListView是一个只读的展示控件,功能相对少
  • 实例演示: 展示表格数据
// Student.cs
......

namespace GatherControlDemo
{
    class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public double Score { get; set; }
        public string Province { get; set; }

     

    }
}



// xaml
<Grid>
	<!--AutoGenerateColumns="False"-->
    <DataGrid x:Name="MyDataGrid"  CanUserAddRows="False" 
    		AlternationCount="2"
    		RowBackground="AliceBlue" 
    		GridLinesVisibility="None"
             FrozenColumnCount="2" >
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
            <DataGridTextColumn Header="Age" Binding="{Binding Age}" />
            <DataGridTextColumn Header="Score" Binding="{Binding Score}" />
        </DataGrid.Columns>
    </DataGrid>
    
</Grid>

// cs
......
namespace GatherControlDemo
{
    public partial class DataGridDemo : Window
    {
        public DataGridDemo()
        {
            InitializeComponent();
            LoadStudentData();
        }

        private void LoadStudentData()
        {
            var students = new List<Student> {
                new Student { Name = "张三", Age = 20, Score = 85.5 },
                new Student { Name = "李四", Age = 22, Score = 59.0 },
                new Student { Name = "王五", Age = 21, Score = 72.5 },
                new Student { Name = "赵六", Age = 19, Score = 91.0 }
            };

            MyDataGrid.ItemsSource = students;
        }

    }
}

  • DataGrid下拉列(DataGridComboBoxColumn)效果实例演示,把上述实例修改一下
// xaml
<DataGrid.Columns>
   <!--修改之处-->
    <DataGridComboBoxColumn Header="Province" SelectedItemBinding="{Binding Province}" DisplayMemberPath="." />
</DataGrid.Columns>

// cs
......

namespace GatherControlDemo
{
  
    public partial class DataGridDemo : Window
    {
		
		// 添加私有属性"_provinces"
        private readonly List<string> _provinces = new List<string> {
            "北京市","天津市","河南省","河北省"
        };

        public DataGridDemo()
        {
            InitializeComponent();
            // 初始化这两个方法
            LoadStudentData();
            ConfigureComboBoxColumn();
        }


        private void ConfigureComboBoxColumn()
        {
            // 找到目标列并设置数据源
            var comboColumn = MyDataGrid.Columns
                .OfType<DataGridComboBoxColumn>()
                .FirstOrDefault(c => c.Header.ToString() == "Province");

            if (comboColumn != null)
            {
                comboColumn.ItemsSource = _provinces;
            }
        }


        private void LoadStudentData()
        {
            ......
        }

    }
}


  • DataGridTemplateColumn图片展示列: 实例演示了表格中如何显示图片
// student.cs

namespace GatherControlDemo
{
    class Student
    {
       ......
        public string ImagePath { get; set; }

    }
}
// xaml

<Window x:Class="GatherControlDemo.DataGridTemplateDemo"
       ......
        Title="学生信息管理系统" Height="500" Width="800"
        WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <Style TargetType="DataGrid">
            <Setter Property="RowBackground" Value="#FFF0F8FF"/>
            <Setter Property="AlternatingRowBackground" Value="#FFE6F1F5"/>
            <Setter Property="BorderBrush" Value="#FFB0C4DE"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="GridLinesVisibility" Value="None"/>
            <Setter Property="FontSize" Value="14"/>
            <Setter Property="CanUserAddRows" Value="False"/>
        </Style>

        <Style TargetType="DataGridColumnHeader">
            <Setter Property="Background" Value="#FF4682B4"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="Padding" Value="10,5"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
        </Style>

        <Style TargetType="DataGridCell">
            <Setter Property="Padding" Value="10,5"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
        </Style>

        <Style TargetType="Image">
           
           
            <Setter Property="Width" Value="60"/>
            <Setter Property="Height" Value="60"/>
            <Setter Property="Stretch" Value="UniformToFill"/>
            <Setter Property="Clip">
                <Setter.Value>
                    <RectangleGeometry Rect="0,0,60,60"/>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <TextBlock Grid.Row="0" Text="学生信息列表" 
                   FontSize="22" FontWeight="Bold" 
                   Margin="0,0,0,15" HorizontalAlignment="Center"
                   Foreground="#FF4682B4"/>

        <DataGrid x:Name="MyDataGrid" Grid.Row="1"
                  AutoGenerateColumns="False"
                  HeadersVisibility="Column"
                  IsReadOnly="True">
            <DataGrid.Columns>
            	<!--插入图片-->
                <DataGridTemplateColumn Header="照片" Width="Auto">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Image Source="{Binding ImagePath}" 
                                   ToolTip="{Binding Name}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

                <DataGridTextColumn Header="姓名" Binding="{Binding Name}" Width="120"/>
                <DataGridTextColumn Header="年龄" Binding="{Binding Age}" Width="80"/>
                <DataGridTextColumn Header="分数" Binding="{Binding Score}" Width="120">
                    <DataGridTextColumn.ElementStyle>
                        <Style TargetType="TextBlock">
                            <Setter Property="HorizontalAlignment" Value="Right"/>
                            <Setter Property="Padding" Value="0,0,10,0"/>
                        </Style>
                    </DataGridTextColumn.ElementStyle>
                </DataGridTextColumn>

                <DataGridComboBoxColumn Header="省份" 
                                        SelectedItemBinding="{Binding Province}"
                                        DisplayMemberPath="." Width="150"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>
// cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

using System.IO;
using System.Reflection;

namespace GatherControlDemo
{
    public partial class DataGridTemplateDemo : Window
    {
        // 省份列表(所有学生共享)
        private readonly List<string> _provinces = new List<string>
        {
            "北京市", "天津市", "河南省", "河北省", "山东省", "山西省", "江苏省"
        };

        public DataGridTemplateDemo()
        {
            InitializeComponent();
            LoadStudentData();
            ConfigureComboBoxColumn();
        }

        private void ConfigureComboBoxColumn()
        {
            // 找到省份列并设置数据源
            var comboColumn = MyDataGrid.Columns
                .OfType<DataGridComboBoxColumn>()
                .FirstOrDefault(c => c.Header.ToString() == "省份");

            if (comboColumn != null)
            {
                comboColumn.ItemsSource = _provinces;
            }
        }

        private void LoadStudentData()
        {
            var students = new List<Student> {
                new Student {
                    Name = "张三",
                    Age = 20,
                    Score = 85.5,
                    Province = "北京市",
                    ImagePath = GetImagePath("student1.jpg")
                },
                new Student {
                    Name = "李四",
                    Age = 22,
                    Score = 59.0,
                    Province = "天津市",
                    ImagePath = GetImagePath("student2.jpg")
                },
                new Student {
                    Name = "王五",
                    Age = 21,
                    Score = 72.5,
                    Province = "河南省",
                    ImagePath = GetImagePath("student3.jpg")
                },
                new Student {
                    Name = "赵六",
                    Age = 19,
                    Score = 91.0,
                    Province = "河北省",
                    ImagePath = GetImagePath("student4.jpg")
                }
            };

            MyDataGrid.ItemsSource = students;
        }

        private string GetImagePath(string imageName)
        {
            // 获取应用程序基目录(项目根目录的上一级)
            string baseDir = AppDomain.CurrentDomain.BaseDirectory;

            // 组合图片路径:基目录 + "Images/" + 图片文件名
            string imagePath = System.IO.Path.Combine(baseDir, "Images", imageName);

            // 检查文件是否存在
            if (File.Exists(imagePath))
            {
                return imagePath;
            }

            // 文件不存在时返回默认图片
            return System.IO.Path.Combine(baseDir, "Images", "default-avatar.jpg");
        }
    }
}

Combox下拉框

  • 作用: 提供下拉选项供用户选择
  • 基础示例
<StackPanel>
    <ComboBox Width="120" Margin="20">
        <ComboBoxItem Content="ComboxItem1" />
        
        <!--插入带图片的文本-->
        <ComboBoxItem>
            <StackPanel Orientation="Horizontal">
                <Image Source="Images/student1.jpg" Width="20" Height="20" />
                <TextBlock Text="ComboxItem2" />
            </StackPanel>
        </ComboBoxItem>

        <ComboBoxItem Content="ComboxItem3" />
		
		<!--插入按钮-->
        <ComboBoxItem>
            <Button Content="ComboxItem4" />
        </ComboBoxItem>
        
        
    </ComboBox>
</StackPanel>
  • 渲染数据示例
// xaml

<StackPanel>
   ......
    <ComboBox x:Name="MyCombox" SelectedValuePath="Name" DisplayMemberPath="Name" SelectionChanged="MyCombox_SelectionChanged" />
</StackPanel>

//cs

namespace GatherControlDemo
{

    public partial class ComboxDemo : Window
    {
        public ComboxDemo()
        {
            InitializeComponent();
            this.Loaded += ComboxDemo_Loaded;
        }

        private void ComboxDemo_Loaded(object sender, RoutedEventArgs e)
        {
            var students = new List<Student> {
                new Student { Name = "张三", Age = 20, Score = 85.5, Province="北京市"},
                new Student { Name = "李四", Age = 22, Score = 59.0, Province="天津市"},
                new Student { Name = "王五", Age = 21, Score = 72.5, Province="河南省"},
                new Student { Name = "赵六", Age = 19, Score = 91.0, Province="河北省"}
            };

            MyCombox.ItemsSource = students;
        }

        private void MyCombox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Console.WriteLine($"你选择的是: {MyCombox.SelectedValue}");

            var student = MyCombox.SelectedItem as Student;

            Console.WriteLine($"你的年龄是: {student.Age}");
        }
    }
}


TabControl选项卡控件

  • 作用: 做Tab内容切换
<TabControl x:Name="MyTabControl">
    
    <TabItem Header="选项1">
        <Border>
            <TextBlock Text="选项1的内容" />
        </Border>
    </TabItem>

    <TabItem>
        <TabItem.Header>
            <StackPanel Orientation="Horizontal">
                <Image Source="Images/student2.jpg" Width="20" Height="20" Margin="1"/>
                <TextBlock Text="选项2" />
            </StackPanel>
        </TabItem.Header>

        <Image Source="Images/pretty.jpg" />

    </TabItem>
    
</TabControl>

TreeView树形控件

  • 作用: 展示树形结构,用的地方很多
  • 注意事项: 一般情况下,这种树形结构不要超过5层
  • 基础示例
<StackPanel>
    <TreeView Name="MyTreeView">
        
        <TreeViewItem Header="Employee1" IsSelected="True">
            <TreeViewItem>
                <TreeViewItem.Header>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="Images/student3.jpg" Width="20" Height="20" />
                        <TextBlock Text="Pretty Girl" />
                    </StackPanel>
                </TreeViewItem.Header>
            </TreeViewItem>
            <TreeViewItem Header="Employee Number" >
                <TreeViewItem Header="12345" />
            </TreeViewItem>
        </TreeViewItem>


        <TreeViewItem Header="Work Days" >
            <TreeViewItem Header="Monday" />
            <TreeViewItem Header="Tuesday" />
            <TreeViewItem Header="Wednesday" />
        </TreeViewItem>

        <TreeViewItem Header="Employee2" >
            <TreeViewItem Header="Dominik Paiha" />
            <TreeViewItem Header="Employee Number" >
                <TreeViewItem Header="98765" />
            </TreeViewItem>
        </TreeViewItem>

    </TreeView>
    
</StackPanel>
  • 进阶示例: 根据"根数据"去渲染"子数据"
// xaml: 就一个壳
<TreeView x:Name="DynamicTreeView" Margin="20" />

// cs

......

namespace GatherControlDemo
{

    public partial class TreeViewDemo : Window
    {
        public TreeViewDemo()
        {
            InitializeComponent();
            // 加载数据源并生成TreeView
            LoadDepartmentDataAndFindRootNode();
        }


        private void LoadDepartmentDataAndFindRootNode()
        {
            var departments = new List<DepartmentData> {

                new DepartmentData{ Id=1, Name="生产部", ParentId=0 },
                new DepartmentData{ Id=2, Name="生管资材", ParentId=1 },
                new DepartmentData{ Id=3, Name="制造一部", ParentId=1 },
                new DepartmentData{ Id=4, Name="制造二部", ParentId=1 },
                new DepartmentData{ Id=5, Name="工程部", ParentId=1 },
                new DepartmentData{ Id=6, Name="生产技术课", ParentId=5 },
                new DepartmentData{ Id=7, Name="设备课", ParentId=5 },
                new DepartmentData{ Id=8, Name="治具", ParentId=6 },
                new DepartmentData{ Id=9, Name="非标自动化", ParentId=6 },

            };
			
			// 获取根节点并根据子节点渲染树型结构
            var rootNode = departments.FirstOrDefault(p => p.ParentId == 0);

            TreeViewItem rootItem = new TreeViewItem()
            {
                Uid = rootNode.Id.ToString(),
                Header = rootNode.Name,
                Tag = rootNode
            };

            BuildTree(departments, rootItem);
            DynamicTreeView.Items.Add(rootItem);
        }

		
		// 查找子节点
        private void BuildTree(List<DepartmentData> menuItems,TreeViewItem parentItem)
        {
            var children = menuItems.Where(p => p.ParentId == Convert.ToInt32(parentItem.Uid));

            foreach (var child in children) {
                TreeViewItem item = new TreeViewItem()
                {
                    Uid = child.Id.ToString(),
                    Header = child.Name,
                    Tag = child
                };
			
				// 递归
                BuildTree(menuItems, item);
                parentItem.Items.Add(item);
            }

        }

    }
}

  • 作用: 展示各种各样的菜单,比如打开,编辑,视图
  • 基础示例: 演示通过菜单打开txt文件
<Grid>

    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>

    <Menu x:Name="MyMenu">
        
        <MenuItem Header="文件">
            <MenuItem Header="新建"  />
            <MenuItem Header="打开"  >
                <MenuItem.Icon>
                    <Image Source="Images/student2.jpg" />
                </MenuItem.Icon>
                <!--绑定点击事件-->
                <MenuItem Header="打开文本" Click="OpenTxtFile" />
                <MenuItem Header="打开数据库" />
                
            </MenuItem>
        </MenuItem>

        <MenuItem Header="编辑" />
        <MenuItem Header="视图" />
        <MenuItem Header="项目" />
        <MenuItem Header="调试" />
        <MenuItem Header="工具" />
        <MenuItem Header="帮助" />

    </Menu>

    <TextBlock x:Name="MyTextBlock" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" />

</Grid>

// cs

......

namespace GatherControlDemo
{
   
    public partial class MenuDemo : Window
    {
        public MenuDemo()
        {
            InitializeComponent();
        }
		
		// 调用notepad.exe来打开txt文件
        private void OpenTxtFile(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dialog = new();
            dialog.Filter = "文本文件|*.txt";
            if (dialog.ShowDialog() == true) {
                System.Diagnostics.Process.Start("notepad.exe",dialog.FileName);
            }
        }
    }
}

  • 利用之前的TreeView示例,构造树型结构来渲染,示例如下
<Grid>

    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
	
	<!--只有一个壳-->
    <Menu x:Name="MyMenu">
       
    </Menu>

    <TextBlock x:Name="MyTextBlock" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" />

</Grid>

// cs
......
namespace GatherControlDemo
{
   
    public partial class MenuDemo : Window
    {
        public MenuDemo()
        {
            InitializeComponent();
            LoadDepartmentDataAndFindRootNode();
        }


        private void LoadDepartmentDataAndFindRootNode()
        {
            var departments = new List<DepartmentData> {

                new DepartmentData{ Id=1, Name="生产部", ParentId=0 },
                new DepartmentData{ Id=2, Name="生管资材", ParentId=1 },
                new DepartmentData{ Id=3, Name="制造一部", ParentId=1 },
                new DepartmentData{ Id=4, Name="制造二部", ParentId=1 },
                new DepartmentData{ Id=5, Name="工程部", ParentId=1 },
                new DepartmentData{ Id=6, Name="生产技术课", ParentId=5 },
                new DepartmentData{ Id=7, Name="设备课", ParentId=5 },
                new DepartmentData{ Id=8, Name="治具", ParentId=6 },
                new DepartmentData{ Id=9, Name="非标自动化", ParentId=6 },

            };


            var rootNode = departments.FirstOrDefault(p => p.ParentId == 0);
            TreeViewItem rootItem = new TreeViewItem()
            {
                Uid = rootNode.Id.ToString(),
                Header = rootNode.Name,
                Tag = rootNode
            };

            BuildTree(departments, rootItem);
            // 修改之处
            MyMenu.Items.Add(rootItem);
        }
		
		// 全盘照搬
        private void BuildTree(List<DepartmentData> menuItems, TreeViewItem parentItem)
        {
            var children = menuItems.Where(p => p.ParentId == Convert.ToInt32(parentItem.Uid));

            foreach (var child in children)
            {
                TreeViewItem item = new TreeViewItem()
                {
                    Uid = child.Id.ToString(),
                    Header = child.Name,
                    Tag = child
                };

                BuildTree(menuItems, item);
                parentItem.Items.Add(item);
            }

        }



        private void OpenTxtFile(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dialog = new();
            dialog.Filter = "文本文件|*.txt";
            if (dialog.ShowDialog() == true) {
                System.Diagnostics.Process.Start("notepad.exe",dialog.FileName);
            }
        }
    }
}

  • 按钮状层级菜单,示例如下
<Grid>

    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
	
	<!--壳+样式渲染-->
    <Menu x:Name="MyMenu" Background="White">
        <Menu.Resources>
            <Style TargetType="MenuItem">
                <Setter Property="Background" Value="White"/>
                <Setter Property="Foreground" Value="Black"/>
                <Setter Property="BorderThickness" Value="1"/>
                <Setter Property="BorderBrush" Value="#FFE0E0E0"/>
            </Style>
        </Menu.Resources>
    </Menu>

    <TextBlock x:Name="MyTextBlock" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" />

</Grid>

// cs

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace GatherControlDemo
{
    public partial class MenuDemo : Window
    {
        public MenuDemo()
        {
            InitializeComponent();
            LoadDepartmentDataAndBuildMenu();
        }

        private void LoadDepartmentDataAndBuildMenu()
        {
            var departments = new List<DepartmentData> {
                new DepartmentData{ Id=1, Name="生产部", ParentId=0 },
                new DepartmentData{ Id=2, Name="生管资材", ParentId=1 },
                new DepartmentData{ Id=3, Name="制造一部", ParentId=1 },
                new DepartmentData{ Id=4, Name="制造二部", ParentId=1 },
                new DepartmentData{ Id=5, Name="工程部", ParentId=1 },
                new DepartmentData{ Id=6, Name="生产技术课", ParentId=5 },
                new DepartmentData{ Id=7, Name="设备课", ParentId=5 },
                new DepartmentData{ Id=8, Name="治具", ParentId=6 },
                new DepartmentData{ Id=9, Name="非标自动化", ParentId=6 },
            };

            // 构建树形结构
            var rootNodes = BuildMenuTree(departments, 0);

            // 创建顶级菜单项
            foreach (var node in rootNodes)
            {
                MenuItem rootItem = CreateMenuItem(node);
                MyMenu.Items.Add(rootItem);
            }
        }

        private List<DepartmentNode> BuildMenuTree(List<DepartmentData> departments, int parentId)
        {
            return departments
                .Where(d => d.ParentId == parentId)
                .Select(d => new DepartmentNode
                {
                    Id = d.Id,
                    Name = d.Name,
                    ParentId = d.ParentId,
                    Children = BuildMenuTree(departments, d.Id)
                })
                .ToList();
        }

        private MenuItem CreateMenuItem(DepartmentNode node)
        {
            var menuItem = new MenuItem
            {
                Header = node.Name,
                Tag = node.Id,
                Background = Brushes.White,
                Foreground = Brushes.Black
            };

            menuItem.Click += MenuItem_Click;

            foreach (var child in node.Children)
            {
                menuItem.Items.Add(CreateMenuItem(child));
            }

            return menuItem;
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            if (sender is MenuItem menuItem)
            {
                MyTextBlock.Text = $"选择了: {menuItem.Header} (ID: {menuItem.Tag})";
            }
        }

        // 树形结构节点类
        private class DepartmentNode
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int ParentId { get; set; }
            public List<DepartmentNode> Children { get; set; } = new List<DepartmentNode>();
        }
    }
}

ContextMenu右键菜单控件

  • 作用: 为控件添加右键菜单的功能
<StackPanel>
    <Border Width="200" Height="40" CornerRadius="10" Background="Brown" >
        <TextBlock Text="右键点击我" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" />
        <Border.ContextMenu>
            <ContextMenu>
                <MenuItem Header="打开记事本" />
                <MenuItem Header="退出" Click="ExitSystem">
                    <MenuItem.Icon>
                        <Image Source="Images/student2.jpg" />
                    </MenuItem.Icon>
                </MenuItem>
            </ContextMenu>
        </Border.ContextMenu>
    </Border>
</StackPanel>

// cs
......

namespace GatherControlDemo
{
    public partial class ContextMenuDemo : Window
    {
        public ContextMenuDemo()
        {
            InitializeComponent();
        }
		
		// 退出系统
        private void ExitSystem(object sender, RoutedEventArgs e)
        {
            Environment.Exit(0);
        }
    }
}


StatusBar状态栏

  • 作用: 指示文件的状态,丢到状态栏的控件可以是图片,进度条或者文字
  • 演示实例如下
<Window x:Class="GatherControlDemo.StatusBarDemo"
        ......
        Title="StatusBarDemo" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Button x:Name="MyBtn" Click="MyBtn_Click" Content="执行" Width="100" Height="50" />
		
		<!--状态栏控件-->
        <StatusBar Grid.Row="1">
            <StatusBarItem Content="xxx公司" />
            <TextBlock x:Name="MytxtBlock" />
            <ProgressBar x:Name="MyProcessBar" Minimum="0" Width="100" />
        </StatusBar>

    </Grid>
</Window>

// cs
......
namespace GatherControlDemo
{
   
    public partial class StatusBarDemo : Window
    {
        public StatusBarDemo()
        {
            InitializeComponent();
        }

        private void MyBtn_Click(object sender, RoutedEventArgs e)
        {
            var dir = new DirectoryInfo(Environment.CurrentDirectory);
            var files = dir.GetFiles();
            MyProcessBar.Maximum = files.Length;
            var rand = new Random();
			// 5. 启动后台任务
            Task.Run(async () => 
            {
				// 使用Dispatcher在UI线程执行操作
                var _ = this.Dispatcher.InvokeAsync(async () =>
                {
                    foreach (var file in files)
                    {	
                        // 更新文本显示(当前文件名)
                        MytxtBlock.Text = file.Name;
                        // 进度条前进一步
                        MyProcessBar.Value++;
                        // 随机延迟(100-800毫秒)
                        await Task.Delay(rand.Next(100, 800));
                    }
                    // 处理完成后隐藏控件
                    MyProcessBar.Visibility = Visibility.Collapsed;
                    MytxtBlock.Visibility = Visibility.Collapsed;
                });

            });
        }
    }
}


按钮点击
  │
  ├─▶ 获取文件列表
  │
  ├─▶ 设置进度条最大值
  │
  └─▶ 启动后台任务
        │
        └─▶ UI线程调度
              │
              ├─▶ 遍历文件:
              │     │
              │     ├─▶ 更新文件名显示
              │     │
              │     ├─▶ 进度+1
              │     │
              │     └─▶ 随机延迟
              │
              └─▶ 完成后隐藏控件



  • 上述实例有Bug,只能执行一次,修复如下
private async void MyBtn_Click(object sender, RoutedEventArgs e)
{
    try
    {
        MyBtn.IsEnabled = false; // 防止重复点击
        MyProcessBar.Value = 0;  // 重置进度
        MyProcessBar.Visibility = Visibility.Visible; // 显示控件
        MytxtBlock.Visibility = Visibility.Visible;

        var files = new DirectoryInfo(Environment.CurrentDirectory).GetFiles();
        MyProcessBar.Maximum = files.Length;
        var rand = new Random();

        foreach (var file in files)
        {
            MytxtBlock.Text = file.Name;
            MyProcessBar.Value++;
            await Task.Delay(rand.Next(100, 800));
        }
    }
    finally
    {
        MyProcessBar.Visibility = Visibility.Collapsed;
        MytxtBlock.Visibility = Visibility.Collapsed;
        MyBtn.IsEnabled = true;
    }
}

//private void MyBtn_Click(object sender, RoutedEventArgs e)
//{
//    Console.WriteLine("xxx");
//    var dir = new DirectoryInfo(Environment.CurrentDirectory);
//    var files = dir.GetFiles();
//    MyProcessBar.Maximum = files.Length;
//    var rand = new Random();

//    Task.Run(async () => 
//    {

//        var _ = this.Dispatcher.InvokeAsync(async () =>
//        {
//            foreach (var file in files)
//            {
//                MytxtBlock.Text = file.Name;
//                MyProcessBar.Value++;
//                await Task.Delay(rand.Next(100, 800));
//            }
//            MyProcessBar.Visibility = Visibility.Collapsed;
//            MytxtBlock.Visibility = Visibility.Collapsed;
//        });

//    });
//}
posted @ 2025-07-01 11:42  清安宁  阅读(8)  评论(0)    收藏  举报