便携式代码库






4.88/5 (9投票s)
便携式代码片段数据库
引言
这个小型的代码数据库实用程序可以存储代码片段,甚至提供语法高亮显示。
背景
如果我需要在其他项目中查找代码片段或源代码,我真的很讨厌这样。在网上搜索免费的、便携的代码数据库后,我决定自己编写一个。
Using the Code
该实用程序使用了 DotNet Fireball 的语法高亮显示器。 我曾经使用 ScintillaNet,但它支持的语言数量有限。
更改代码语言非常简单
private void SetLanguage(string syntax)
{
int CodeSyntax = 0;
try
{
CodeSyntax = (Int32)Enum.Parse(typeof(SyntaxEditor.enumSyntax), syntax);
syntaxEditor1.CodeSyntaxIndex = CodeSyntax;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
由于这是一个便携式应用程序(只有一个EXE),我使用 XML 作为数据库。
为了创建数据库的结构,我创建了一个 CreateNEWDB()
方法,该方法只是创建列等。
private void CreateNewDB()
{
DataColumn dcol;
try
{
//Create new Datatable
dtCodeEntries = new DataTable("CodeEntry");
//Create ID column.
dcol = new DataColumn("ID",typeof(int));
dcol.Caption = "ID";
//Add column to Datatable
dtCodeEntries.Columns.Add(dcol);
//Create Name column.
dcol = new DataColumn("Name", typeof(string));
dcol.Caption = "Name";
dcol.MaxLength = 99;
//Add column to Datatable
dtCodeEntries.Columns.Add(dcol);
//Create Entry / Code column.
dcol = new DataColumn("Entry", typeof(string));
dcol.MaxLength = 8000;
dcol.Caption = "Code Entry";
//Add column to Datatable
dtCodeEntries.Columns.Add(dcol);
//Create Language column.
dcol = new DataColumn("Language", typeof(string));
dcol.Caption = "Language";
dcol.MaxLength = 10;
//Add column to Datatable
dtCodeEntries.Columns.Add(dcol);
codeDS.Tables.Add(dtCodeEntries);
btnNew.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
该项目使用未类型的 DataSet
,它使用 ReadXML()
方法来填充它。加载数据库也很简单
private void LoadExternalDB()
{
if (dbPath != string.Empty)
{
try
{
//Reset the dataset
codeDS = new DataSet();
//Get the data from the XML database into our dataset
codeDS.ReadXml(dbPath);
//Populate the DataTable with all the entries
PopulateDataTable();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
private void PopulateDataTable()
{
if (codeDS != null)
{
if (codeDS.Tables.Count > 0)
{
//Clear our List
CodeEntries.Clear();
//Build up the list from the DataTable's Rows
foreach (DataRow dr in codeDS.Tables[0].Rows)
{
CodeEntry ce = new CodeEntry();
//setup the CodeEntry from the DataRow
ce.Fill(dr);
//Ad the CodeEntry to our List
CodeEntries.Add(ce);
}
}
}
}
为了简化界面/数据库过渡,我使用 List
来存储 CodeEntry
。 CodeEntry
是一个类似于数据库条目结构的类。
public class CodeEntry
{
public int ID { get; set; }
public string Name { get; set; }
public string Entry { get; set; }
public string Language { get; set; }
public CodeEntry()
{
ID = -1;
Name = "";
Entry = "";
Language = "";
}
/// <summary>
/// Fill the CodeEntry from the DataRow.
/// </summary>
/// <param name="dr">The DataRow to fill from</param>
/// <remarks>
/// This method is a bit over the top as it caters for future growth.
/// A simple hardcoded method would suffice, but why do a bad job now...
/// </remarks>
public void Fill(System.Data.DataRow dr)
{
System.ComponentModel.PropertyDescriptorCollection props =
System.ComponentModel.TypeDescriptor.GetProperties(this);
//Loop thru the properties
for (int i = 0; (i < props.Count); i = (i + 1))
{
//Get the property details
System.ComponentModel.PropertyDescriptor prop = props[i];
//Don't try to set a read-only property.
if ((prop.IsReadOnly != true))
{
try
{
//Check that the data row value isn't null
if ((dr[prop.Name].Equals(System.DBNull.Value) != true))
{
//Check if the property is the same
//as the database type otherwise convert.
if ((prop.PropertyType.Equals(dr[prop.Name].GetType()) != true))
{
prop.SetValue(this, prop.Converter.ConvertFrom(dr[prop.Name]));
}
else
{
prop.SetValue(this, dr[prop.Name]);
}
}
}
catch (System.Exception)
{
}
}
}
}
}
CodeEntry
的 Fill
方法使从 DataRow
填充 CodeEntry
变得简单。此方法可能有点过头,但它可以轻松地向类添加更多属性而无需重写。
使用 WriteXML()
方法可以轻松地将数据库保存到 XML。
private void SaveAndReload()
{
try
{
//Convert the List to a DataTable so that we can save it to XML
dtCodeEntries = ToDataTable(CodeEntries);
dtCodeEntries.TableName = "CodeEntry";
codeDS = new DataSet();
codeDS.Tables.Add(dtCodeEntries);
if (dbPath == string.Empty)
{
if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
dbPath = saveFileDialog1.FileName;
}
}
//Save DB to XML
codeDS.WriteXml(dbPath);
//Reload Info
LoadDB(false);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
这个 SaveAndReload
方法在保存和删除时使用,因为它将我们的 CodeEntry
List
转换为 DataTable
。 然后将此 DataTable
添加到 DataSet
,后者又调用 WriteXML()
方法将我们的数据库保存到 XML。 WriteXML
方法也存在于 DataTable
对象上,但为了未来的开发,我们可能需要更多 DataTable
来存储类别等。
在初始版本发布后发现了一个问题,即 ScintillaNet 控件需要 SciLexer.dll。(感谢 Petr Kohout。)
为了保持应用程序的便携性,我对启动时提取这些 .dll 文件进行了一些修改。
private void ExtractDLLs()
{
try
{
//View embedded resource names
//Assembly asm = this.GetType().Assembly;
//string[] resNames = asm.GetManifestResourceNames();
List<byte[]> EmbeddedDlls = new List<byte[]>();
EmbeddedDlls.Add(Properties.Resources.Fireball_CodeEditor);
EmbeddedDlls.Add(Properties.Resources.Fireball_CodeEditor_SyntaxFiles);
EmbeddedDlls.Add(Properties.Resources.Fireball_Core);
EmbeddedDlls.Add(Properties.Resources.Fireball_SyntaxDocument);
EmbeddedDlls.Add(Properties.Resources.Fireball_Win32);
EmbeddedDlls.Add(Properties.Resources.Fireball_Windows_Forms);
int index = 0;
startPath = Application.StartupPath;
string[] dllNames = new string[] { "Fireball.CodeEditor",
"Fireball.CodeEditor.SyntaxFiles", "Fireball.Core",
"Fireball.SyntaxDocument", "Fireball.Win32",
"Fireball.Windows.Forms" };
foreach (byte[] dllBuffer in EmbeddedDlls)
{
string dllName = dllNames[index];
if (!File.Exists(startPath + @"\" + dllName + ".dll"))
{
CreateFileFromByteArray(dllBuffer, startPath + @"\" + dllName + ".dll");
}
index++;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
有更好的方法可以获取嵌入式资源 (DLL),但我遇到了资源管理器的问题。 它一直在 CodeBasePortable.Resources.resources
中搜索资源。 我使用了程序集来向我显示资源名称,以便我可以指定确切的名称,但它仍然没有检索到。
//View embedded resource names
Assembly asm = this.GetType().Assembly;
string[] resNames = asm.GetManifestResourceNames();
我不得不诉诸暴力,并使用 Properties.Resources
途径来提取 DLL。
从资源管理器获取文件后,我们需要将 .dll 写入启动路径。
public static void CreateFileFromByteArray(byte[] barrFile, string strDestinationPath)
{
try
{
FileStream output = new FileStream(strDestinationPath,
FileMode.Create, FileAccess.Write);
BinaryWriter writer = new BinaryWriter(output);
writer.Write(barrFile);
writer.Close();
output.Close();
}
catch (Exception exception1)
{
MessageBox.Show("There was a problem writing " +
"the file to the path " + strDestinationPath);
}
}
关注点
类 CodeEntry
使操作代码条目变得容易。 填充它们很容易,而且可以面向未来。
主项目提供了一种将 List
转换为 DataTable
的方法,以便轻松保存数据。
ScintillaNET 语法高亮显示控件可以轻松地突出显示代码,但证明受到限制。 我选择了 Dotnet Fireball,因为它具有大量的代码语言支持。
我还包括了 CodeBase 插件的项目。 这是一个可以从 IDE 启动的 Visual Studio 2010 插件。 这里的巨大优势是您现在可以将 Code Base 作为开发环境的一部分,并将代码数据库随 CodeBase Portable 一起携带。
可能的解决方案问题
由于我扔掉了 ScintillaNEt,因此不应该有任何解决方案问题,但请告知我任何问题,以便我可以修复它们。
历史
第一个版本使用 ScintillaNet 进行语法高亮显示,但证明受到限制。 新版本改用 DotNet Fireball。
这仍然非常简单。 后续修订可能包括类别等。