• 基于WPF重复造轮子,写一款数据库文档管理工具(一)


    项目背景

    公司业务历史悠久且复杂,数据库的表更是多而繁杂,每次基于老业务做功能开发都需要去翻以前的表和业务代码。需要理解旧的表的用途以及包含的字段的含义,表少还好说,但是表一多这就很浪费时间,而且留下来的文档都是残缺不全,每次查一些表的含义都要捯饬很久。在网上搜索关于数据库文档管理工具搜到最多的就是Screw和DBCHM,一个是基于Java的工具、另一个则是bug很多,表一多就一直转圈圈进不去。所以自己就动手开发了这款SmartSQL的工具。

    它是一款基于.Net 4.6.1WPF开发的一款数据库文档管理,不仅支持多种数据库(SQLServerMySQLPostgreSQLSQLite)表、视图、存储过程的查询管理,还支持对其进行导出成离线文档,支持的文档包括CHMWordExcelPDFHTMLXmlJsonMarkDown等多种格式。

    现在将它开源分享出来,供更多的小伙伴使用和参考学习(文末附开源地址)。

    技术栈

    • .Net 4.6.1
    • WPF
    • HandyControl
    • SqlSugar
    • AvalonEdit
    • SharpVectors

    HandyControl是一款非常优秀的WPF框架,做出来的页面都很漂亮,所以我们选择使用它。
    Nuget中引用HandyControl

    一.菜单栏

    然后我们要实现一个基于WPF边框上的菜单栏,刚好HandyControl中有这么一个菜单栏的控件,
    下面就是实现菜单栏的方法:
    `

    <hc:GlowWindow.NonClientAreaContent>
        <StackPanel Height="29" Margin="25,0,0,0">
            <Menu HorizontalAlignment="Left">
                <MenuItem
                    x:Name="SwitchMenu"
                    Cursor="Hand"
                    FontWeight="Bold"
                    Foreground="{DynamicResource DarkPrimaryBrush}"
                    Header="选择连接">
                    <MenuItem.Icon>
                        <Path
                            Data="{StaticResource DownGeometry}"
                            Fill="{DynamicResource DarkPrimaryBrush}"
                            Stretch="Uniform" />
                    MenuItem.Icon>
                    <MenuItem.ItemTemplate>
                        <HierarchicalDataTemplate>
                            <MenuItem
                                Width="160"
                                Margin="0"
                                Padding="0"
                                HorizontalAlignment="Left"
                                VerticalAlignment="Stretch"
                                Click="SwitchMenu_Click"
                                Cursor="Hand"
                                FontWeight="Normal"
                                Header="{Binding ConnectName}">
                                <MenuItem.Icon>
                                    <svgc:SvgViewbox
                                        Width="16"
                                        Height="16"
                                        HorizontalAlignment="Left"
                                        IsHitTestVisible="False"
                                        Source="{Binding Icon}" />
                                MenuItem.Icon>
                            MenuItem>
                        HierarchicalDataTemplate>
                    MenuItem.ItemTemplate>
                MenuItem>
                <MenuItem
                    Name="MenuConnect"
                    Cursor="Hand"
                    FontWeight="Bold"
                    Foreground="{DynamicResource DarkPrimaryBrush}"
                    Header="文件">
                    <MenuItem.Icon>
                        <Path
                            Data="{StaticResource FileGeometry}"
                            Fill="{DynamicResource DarkPrimaryBrush}"
                            Stretch="Uniform" />
                    MenuItem.Icon>
                    <MenuItem
                        Name="AddConnect"
                        Click="AddConnect_OnClick"
                        FontWeight="Normal"
                        Header="新建连接">
                        <MenuItem.Icon>
                            <Path
                                Data="{StaticResource NewConnectGeometry}"
                                Fill="{DynamicResource DarkPrimaryBrush}"
                                Stretch="Uniform" />
                        MenuItem.Icon>
                    MenuItem>
                    <MenuItem
                        Name="ImportMark"
                        Click="ImportMark_OnClick"
                        FontWeight="Normal"
                        Header="导入备注">
                        <MenuItem.Icon>
                            <Path
                                Data="{StaticResource ImportGeometry}"
                                Fill="{DynamicResource DarkPrimaryBrush}"
                                Stretch="Uniform" />
                        MenuItem.Icon>
                    MenuItem>
                    <MenuItem
                        Name="ExportDoc"
                        Click="ExportDoc_OnClick"
                        FontWeight="Normal"
                        Header="导出文档">
                        <MenuItem.Icon>
                            <Path
                                Data="{StaticResource ExportGeometry}"
                                Fill="{DynamicResource DarkPrimaryBrush}"
                                Stretch="Uniform" />
                        MenuItem.Icon>
                    MenuItem>
                MenuItem>
                <MenuItem
                    Name="MenuGroup"
                    Click="MenuGroup_OnClick"
                    Cursor="Hand"
                    FontWeight="Bold"
                    Foreground="{DynamicResource DarkPrimaryBrush}"
                    Header="分组">
                    <MenuItem.Icon>
                        <Path
                            Data="{StaticResource GroupGeometry}"
                            Fill="{DynamicResource DarkPrimaryBrush}"
                            Stretch="Uniform" />
                    MenuItem.Icon>
                MenuItem>
                <MenuItem
                    Name="MenuSetting"
                    Click="MenuSetting_OnClick"
                    Cursor="Hand"
                    FontWeight="Bold"
                    Foreground="{DynamicResource DarkPrimaryBrush}"
                    Header="设置">
                    <MenuItem.Icon>
                        <Path
                            Data="{StaticResource SettingGeometry}"
                            Fill="{DynamicResource DarkPrimaryBrush}"
                            Stretch="Uniform" />
                    MenuItem.Icon>
                MenuItem>
                <MenuItem
                    Name="MenuAbout"
                    Click="MenuAbout_OnClick"
                    Cursor="Hand"
                    FontWeight="Bold"
                    Foreground="{DynamicResource DarkPrimaryBrush}"
                    Header="关于">
                    <MenuItem.Icon>
                        <Path
                            Data="{StaticResource InfoGeometry}"
                            Fill="{DynamicResource DarkPrimaryBrush}"
                            Stretch="Uniform" />
                    MenuItem.Icon>
                MenuItem>
            Menu>
        StackPanel>
    hc:GlowWindow.NonClientAreaContent>
    
    
    折叠

    其中有个小插曲,在WPF中是默认不支持svg图形的,所以我们需要引用一个组件:SharpVectors,它的使用方法是这样的,引用svg界面需要引入下面语句:
    xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
    然后引用要显示的svg图形:

    <svgc:SvgViewbox
              Width="16"
              Height="16"
              HorizontalAlignment="Left"
              IsHitTestVisible="False"
              Source="{Binding Icon}" />
    

    二.左侧菜单栏

    然后就是左侧的菜单栏,我们要实现一个数据库的选择和数据库对象的搜索,可以搜索相关表、视图、存储过程等对象。
    首先我们要对我们的主界面进行一个简单的1:1:1的竖向布局,分别为左侧菜单栏、中间可以移动的分隔栏、右面的主界面:

    
        
        <Grid x:Name="GridMain" Background="{StaticResource CloudDrawingBrush}">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
            Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="3.3*" MinWidth="200" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="6.6*" />
            Grid.ColumnDefinitions>
    Grid>
    

    现在我们要实现一个左侧树形的菜单栏,我们使用的是WPF里面的TreeView控件进行实现这样一个功能,下面是相关代码:

    
            <DockPanel Grid.Row="0" Grid.Column="0">
                <hc:SimplePanel>
                    <Border
                        Margin="5,5,0,5"
                        Background="{DynamicResource RegionBrush}"
                        CornerRadius="{Binding CornerRadius}">
                        <Grid
                            Height="Auto"
                            Margin="5"
                            Background="Transparent">
                            <TextBox x:Name="HidSelectDatabase" Visibility="Hidden" />
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="8*" />
                                    <ColumnDefinition Width="1*" MinWidth="30" />
                                Grid.ColumnDefinitions>
                                <ComboBox
                                    x:Name="SelectDatabase"
                                    Height="30"
                                    VerticalAlignment="Top"
                                    HorizontalContentAlignment="Stretch"
                                    hc:BorderElement.CornerRadius="5"
                                    hc:InfoElement.Placeholder="请选择数据库"
                                    Cursor="Hand"
                                    IsTextSearchEnabled="True"
                                    SelectionChanged="SelectDatabase_OnSelectionChanged"
                                    Style="{StaticResource ComboBoxExtend}"
                                    Text="{Binding DbName}">
                                    <ComboBox.ItemTemplate>
                                        <DataTemplate>
                                            <StackPanel VerticalAlignment="Center" Orientation="Horizontal">
                                                <Image
                                                    Width="11"
                                                    Height="15"
                                                    Source="/SmartSQL;component/Resources/Img/dataBase.ico" />
                                                <TextBlock
                                                    Margin="5,0,0,0"
                                                    HorizontalAlignment="Center"
                                                    VerticalAlignment="Center"
                                                    Text="{Binding DbName}" />
                                            StackPanel>
                                        DataTemplate>
                                    ComboBox.ItemTemplate>
                                ComboBox>
                                <Button
                                    Name="BtnFresh"
                                    Grid.Column="2"
                                    Margin="0,0,0,0"
                                    Padding="4"
                                    VerticalAlignment="Top"
                                    Background="Transparent"
                                    BorderThickness="0"
                                    Click="BtnFresh_OnClick"
                                    Cursor="Hand">
                                    <Button.Content>
                                        <Image Source="/SmartSQL;component/Resources/Img/Refresh.png" Stretch="Fill" />
                                    Button.Content>
                                Button>
                            Grid>
                            <hc:SearchBar
                                x:Name="SearchMenu"
                                Height="30"
                                Margin="0,34,0,0"
                                Padding="5,0,5,0"
                                VerticalAlignment="Top"
                                HorizontalContentAlignment="Stretch"
                                hc:BorderElement.CornerRadius="5"
                                hc:InfoElement.Placeholder="搜索数据表/视图/存储过程"
                                FontSize="13"
                                ShowClearButton="True"
                                Style="{StaticResource SearchBarPlus}"
                                TextChanged="SearchMenu_OnTextChanged" />
                            <TabControl
                                x:Name="TabLeftType"
                                Margin="0,65,0,40"
                                SelectionChanged="TabLeftType_OnSelectionChanged"
                                Style="{StaticResource TabControlInLine}">
                                <TabItem
                                    x:Name="TabAllData"
                                    Cursor="Hand"
                                    Header="全部"
                                    IsSelected="True" />
                                <TabItem
                                    x:Name="TabGroupData"
                                    Cursor="Hand"
                                    Header="分组"
                                    IsSelected="False" />
                                
                            TabControl>
                            <TreeView
                                x:Name="TreeViewTables"
                                Margin="0,100,0,0"
                                VerticalAlignment="Top"
                                BorderThickness="0"
                                ItemsSource="{Binding TreeViewData}"
                                SelectedItemChanged="SelectedTable_OnClick">
                                <TreeView.ItemContainerStyle>
                                    <Style BasedOn="{StaticResource TreeViewItemBaseStyle}" TargetType="{x:Type TreeViewItem}">
                                        <Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
                                        <Setter Property="FontWeight" Value="{Binding FontWeight}" />
                                        <Setter Property="FontSize" Value="12" />
                                        <Setter Property="Visibility" Value="{Binding Visibility}" />
                                        <Setter Property="Foreground" Value="{Binding TextColor}" />
                                        <Setter Property="Cursor" Value="Hand" />
                                        
                                        <EventSetter Event="RequestBringIntoView" Handler="EventSetter_OnHandler" />
                                        <Style.Triggers>
                                            <Trigger Property="IsSelected" Value="True">
                                                <Setter Property="FontWeight" Value="Bold" />
                                            Trigger>
                                        Style.Triggers>
                                    Style>
                                TreeView.ItemContainerStyle>
                                <TreeView.ContextMenu>
                                    
                                    <ContextMenu Visibility="Visible">
                                        <MenuItem
                                            x:Name="MenuSelectedItem"
                                            Padding="5,0,5,0"
                                            VerticalAlignment="Center"
                                            Click="MenuSelectedItem_OnClick"
                                            Cursor="Hand"
                                            Header="复制对象名" />
                                    ContextMenu>
                                TreeView.ContextMenu>
                                <TreeView.ItemTemplate>
                                    <HierarchicalDataTemplate DataType="{x:Type models:TreeNodeItem}" ItemsSource="{Binding Children}">
                                        <StackPanel Orientation="Horizontal">
                                            <svgc:SvgViewbox
                                                Width="12"
                                                Height="12"
                                                Margin="0,0,5,0"
                                                HorizontalAlignment="Left"
                                                Source="{Binding Icon}" />
                                            <TextBlock
                                                VerticalAlignment="Center"
                                                FontSize="12"
                                                Text="{Binding DisplayName}"
                                                ToolTip="{Binding DisplayName}" />
                                        StackPanel>
                                    HierarchicalDataTemplate>
                                TreeView.ItemTemplate>
                            TreeView>
                            <Grid
                                x:Name="NoDataText"
                                Margin="0,100,0,5"
                                HorizontalAlignment="Stretch"
                                Background="White"
                                Cursor="Arrow">
                                <local:NoDataArea
                                    x:Name="NoDataAreaText"
                                    Margin="0"
                                    HorizontalAlignment="Center"
                                    ShowType="All" />
                            Grid>
                            <Grid
                                Margin="0"
                                VerticalAlignment="Bottom"
                                Visibility="Hidden">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="4*" />
                                    <ColumnDefinition Width="6*" />
                                    <ColumnDefinition Width="Auto" />
                                Grid.ColumnDefinitions>
                                <Grid>
                                    <ComboBox
                                        x:Name="CbTargetConnect"
                                        Height="26"
                                        VerticalAlignment="Bottom"
                                        HorizontalContentAlignment="Left"
                                        hc:InfoElement.Placeholder="目标连接"
                                        Cursor="Hand"
                                        DisplayMemberPath="ConnectName"
                                        IsTextSearchEnabled="True"
                                        SelectedValuePath="DbMasterConnectString"
                                        SelectionChanged="CbTargetConnect_OnSelectionChanged"
                                        Style="{StaticResource ComboBoxExtend}" />
                                Grid>
                                <Grid Grid.Column="1" Margin="5,0,0,0">
                                    <ComboBox
                                        x:Name="CbTargetDatabase"
                                        MinWidth="50"
                                        VerticalAlignment="Bottom"
                                        HorizontalContentAlignment="Left"
                                        hc:InfoElement.Placeholder="目标数据库"
                                        Cursor="Hand"
                                        IsTextSearchEnabled="True"
                                        Style="{StaticResource ComboBoxExtend}" />
                                Grid>
                                <Grid Grid.Column="2">
                                    
                                    <Button
                                        x:Name="BtnCompare"
                                        Height="30"
                                        Margin="5,5,0,0"
                                        HorizontalAlignment="Right"
                                        hc:BorderElement.CornerRadius="6"
                                        hc:IconElement.Geometry="{StaticResource CompareGeometry}"
                                        Click="BtnCompare_OnClick"
                                        Content="差异比较"
                                        Cursor="Hand" />
                                Grid>
                            Grid>
                            
                            <hc:LoadingLine
                                x:Name="LoadingLine"
                                Margin="0,0,0,0"
                                Visibility="Collapsed" />
                        Grid>
                    Border>
                hc:SimplePanel>
            DockPanel>
    
    折叠

    在这里我没有详细介绍底层c#的相关代码,里面逻辑有些复杂感兴趣的可以去我的开源项目中学习。在上面的左侧菜单代码中,我们使用的不仅有TreeView控件、也有ContextMenuhc:LoadingLine等控件,还有自己写的自定义控件。

    其实WPF要比WinForm好用不少,不仅支持MVVM数据绑定还支持灵活的页面渲染,自从用了WPF再也不用WinForm了。

    今天分享暂时到这里,下一篇讲介绍DataGrid表格数据绑定及相关条件搜索。下面是工具的开源地址,感兴趣的可以Clone下来学习一下。码砖不易,喜欢的麻烦点下Star.

    开源地址

    https://gitee.com/izhaofu/SmartSQL


  • 相关阅读:
    Centos7安装KingBaseES9(人大金仓V9)
    对boot项目拆分成cloud项目的笔记
    使用 PyTorch 搭建网络 - train_py篇
    【C语言】归并排序
    学习记忆——数学篇——顺口溜记忆法+谐音记忆法+其他
    【Spatial-Temporal Action Localization(三)】论文阅读2018年
    Acwing.4741 魔法百合井(动态规划)
    造车先做三蹦子-之二:自制数据集(5x5数据集)230102
    Outlook屏蔽Jira AI提醒
    Scala入门到精通(尚硅谷学习笔记)章节四——输入和输出
  • 原文地址:https://www.cnblogs.com/izhaofu/p/smartsql1.html