公司業務歷史悠久且複雜,資料庫的表更是多而繁雜,每次基於老業務做功能開發都需要去翻以前的表和業務代碼。需要理解舊的表的用途以及包含的欄位的含義,表少還好說,但是表一多這就很浪費時間,而且留下來的文檔都是殘缺不全,每次查一些表的含義都要捯飭很久。在網上搜索關於資料庫文檔管理工具搜到最多的就是Screw... ...
項目背景
公司業務歷史悠久且複雜,資料庫的表更是多而繁雜,每次基於老業務做功能開發都需要去翻以前的表和業務代碼。需要理解舊的表的用途以及包含的欄位的含義,表少還好說,但是表一多這就很浪費時間,而且留下來的文檔都是殘缺不全,每次查一些表的含義都要捯飭很久。在網上搜索關於資料庫文檔管理工具搜到最多的就是Screw和DBCHM,一個是基於Java的工具、另一個則是bug很多,表一多就一直轉圈圈進不去。所以自己就動手開發了這款SmartSQL的工具。
它是一款基於.Net 4.6.1
、WPF
開發的一款資料庫文檔管理,不僅支持多種資料庫(SQLServer
、MySQL
、PostgreSQL
、SQLite
)表、視圖、存儲過程的查詢管理,還支持對其進行導出成離線文檔,支持的文檔包括CHM
、Word
、Excel
、PDF
、HTML
、Xml
、Json
、MarkDown
等多種格式。
現在將它開源分享出來,供更多的小伙伴使用和參考學習(文末附開源地址)。
技術棧
-
.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的豎向佈局,分別為左側菜單欄、中間可以移動的分隔欄、右面的主界面:
<!-- 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
控制項、也有ContextMenu
、hc:LoadingLine
等控制項,還有自己寫的自定義控制項。
其實WPF要比WinForm好用不少,不僅支持MVVM數據綁定還支持靈活的頁面渲染,自從用了WPF再也不用WinForm了。
今天分享暫時到這裡,下一篇講介紹DataGrid表格數據綁定及相關條件搜索。下麵是工具的開源地址,感興趣的可以Clone下來學習一下。碼磚不易,喜歡的麻煩點下Star.
開源地址
https://gitee.com/izhaofu/SmartSQL
學無止境,貴在積累