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

  • 基于WPF重复造轮子,写一款数据库文档管理工具(一)已关闭评论
  • 162 次浏览
  • A+
所属分类:.NET技术
摘要

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


项目背景

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

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

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

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

技术栈

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

HandyControl是一款非常优秀的WPF框架,做出来的页面都很漂亮,所以我们选择使用它。
Nuget中引用HandyControl
基于WPF重复造轮子,写一款数据库文档管理工具(一)

一.菜单栏

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

然后我们要实现一个基于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的竖向布局,分别为左侧菜单栏、中间可以移动的分隔栏、右面的主界面:

     <!--  Main区域  -->     <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" />                             <!--<TabItem                                 x:Name="TabFavData"                                 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>                         <!--  数据加载Loading  -->                         <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

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