发布文章的目的即是学习也是分享保存。
目录
1、简单的界面设计
程序分为脚本编辑框,操作、结果显示栏。 脚本编辑栏:可以编写自己想要的代码。
操作栏:其中脚本操作可以手动导入代码,也可以导出代码。预选为.txt文本格式,和支持其他格式。导出功能可以导出代码,保存格式只设置了.txt格式。
结果栏:点击编译显示编译结果,点击运行显示运行结果,填入命名空间、类名、方法可以简单显示指定的方法结果(建议是复制到文本框中,否则可能会报错)。
2、实现代码
(1)用到的变量字段
/// CSarpe关键字
private string[] _keyWords = { "abstract", "as", "base", "bool",
"break", "byte", "case","catch","char", "checked", "class", "const",
"continue", "decimal", "default","delegate", "do", "double", "else",
"enum", "event", "explicit", "extern","false", "finally", "fixed",
"float", "for", "foreach", "goto", "if", "implicit","in", "int",
"interface", "internal", "is", "lock", "long", "namespace", "new",
"null", "object", "operator", "out", "override", "params", "partial", "private",
"protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short",
"sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw",
"true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using",
"virtual", "void", "volatile", "while","get","set" };
/// 选择文件
private OpenFileDialog openFileDialog1 = new OpenFileDialog();
/// 编译结果
CompilerResults Result = null;
/// 用于判断特殊按键不做rtb文本发生变化事件处理(如:Enter键、Table键)
bool isEnter = false;
(
(2)窗体初始化、加载
public Form1()
{
InitializeComponent();
this.MaximumSize = new System.Drawing.Size(760, 650);
this.MinimumSize = new System.Drawing.Size(760, 650);
this.rtbScriptCode.KeyDown +=
new System.Windows.Forms.KeyEventHandler(this.rtbKeyDownEnter);
}
private void Form1_Load(object sender, EventArgs e)
{
rtbScriptCode.Multiline = true;
rtbScriptCode.WordWrap = true;
}
(3)执行操作:编译、运行
/// 点击编译按钮
private void btnCompile_Click(object sender, EventArgs e)
{
if (rtbScriptCode.Text.ToString().Trim().Length < 1)
{
AppendInfo("Code Null"); return;
}
CompileCode();
CompilerEffect();
}
/// 点击运行按钮
private void btn02Run_Click(object sender, EventArgs e)
{
if (rtbScriptCode.Text.ToString().Trim().Length < 1)
{ AppendInfo("Code Null"); return; }
CompileCode();
// 通过反射,调用实例
if (Result != null)
{
if (tbNamespace.Text.Trim().Length < 1 ||
tbMethodName.Text.Trim().Length < 1) return;
try
{
AppendInfo("开始运行.....");
Assembly objAssembly = Result.CompiledAssembly;
object objHelloWorld =
objAssembly.CreateInstance($"{tbNamespace.Text}.{tbClassName.Text}");
MethodInfo objMI = objHelloWorld.GetType().GetMethod(tbMethodName.Text);
object ReValue = objMI.Invoke(objHelloWorld, null);
AppendInfo(ReValue);
}
catch (Exception ex)
{
AppendInfo("编译失败:");
AppendInfo(ex.Message);
}
}
else{ MessageBox.Show("执行未编译代码!"); }
}
(4)编译功能方法
public void CompileCode()
{
AppendInfo("编译开始.....");
//【1】新建C#代码生成器和代码编译器的实例
CodeDomProvider Provider = CodeDomProvider.CreateProvider("CSharp");
//【2】配置用于调用编译器的参数
CompilerParameters Parameters = new CompilerParameters();
Parameters.ReferencedAssemblies.Add("System.dll");
Parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
Parameters.ReferencedAssemblies.Add("System.Linq.dll");
Parameters.GenerateExecutable = false;
Parameters.GenerateInMemory = true;
//【3】启动编译
Result = Provider.CompileAssemblyFromSource(Parameters, rtbScriptCode.Text);
if (Result.Errors.HasErrors)
{
AppendInfo("编译错误:");
foreach (CompilerError err in Result.Errors)
{
AppendInfo(err.ErrorText);
}
}
else
{
AppendInfo("编译成功。");
}
}
(5)高亮显示
/// 关键字高亮效果
private void HighlightKeywords()
{
rtbScriptCode.Font = new Font("Consolas", 12);
foreach (string keyword in _keyWords)
{
int startIndex = 0; //索引
//小于文本长度
while (startIndex < rtbScriptCode.TextLength)
{
//仅定位关键字全字的搜索索引
int index = rtbScriptCode.Find(keyword, startIndex, RichTextBoxFinds.WholeWord);
if (index == -1) break;
rtbScriptCode.SelectionStart = index;
rtbScriptCode.SelectionLength = keyword.Length;
rtbScriptCode.SelectionColor = Color.Blue;
startIndex = index + keyword.Length;
}
}
}
/// 注释高亮效果
private void HighlightComments()
{
// 使用正则表达式查找所有注释,并将其文本颜色设置为灰色
Regex regex = new Regex(@"(?://.*?$|/\*.*?\*/)",
RegexOptions.Multiline | RegexOptions.Singleline);
MatchCollection matches = regex.Matches(rtbScriptCode.Text);
int startIndex = rtbScriptCode.SelectionStart;
int length = rtbScriptCode.SelectionLength;
foreach (Match match in matches)
{
rtbScriptCode.Select(match.Index, match.Length);
rtbScriptCode.SelectionColor = Color.Green;
}
rtbScriptCode.Select(startIndex, length);
}
/// 调用方法高亮显示
public void CompilerEffect()
{
HighlightKeywords();
HighlightComments();
}
/// 文本发生改变
private void rtbScriptCode_TextChanged(object sender, EventArgs e)
{
int index = rtbScriptCode.SelectionStart; //插入位置
if (!isEnter)
{
CompilerEffect();
if (index != -1)
{
rtbScriptCode.SelectionStart = index;
rtbScriptCode.SelectionLength = 0;
}
return;
}
}
(6)其它
/// Table键效果
private void rtbScriptCode_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Tab && !(rtbScriptCode.ReadOnly) && !(rtbScriptCode.Enabled))
{
int selectionStart = rtbScriptCode.SelectionStart;
rtbScriptCode.SelectedText = "\t";
rtbScriptCode.SelectionStart = selectionStart + 1;
e.SuppressKeyPress = true;
}
}
/// 文本框中指定按下指定键,不进行关键字高亮操作(高亮操作导致重画会)
private void rtbKeyDownEnter(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Tab || e.KeyCode == Keys.Space)
isEnter = true;
else isEnter = false;
}
/// 文本域鼠标右键
private void rtbScriptCode_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button.ToString().Equals("Right")) rtbScriptCode.SelectAll();
}
/// 追加字符
private void AppendInfo(object Info)
{
tb01CompileResult.Text = Info + "\n\r";
}
/// 导出代码
private void btn03Save_Click(object sender, EventArgs e)
{
if ((rtbScriptCode.Text.Trim().Length) < 1) return;
string fileName = tbFileName.Text;
string path = @"C:\Users\qin\Desktop\TeseCompile\" + $"{fileName}{labelFilePostfix.Text}";
//确认保存,保存方式
bool saveMethod = false;
//保存文件
if (DialogResult.Yes == MessageBox.Show(path, "保存", MessageBoxButtons.YesNo))
{
if (File.Exists(path))
{
//是否替换文件
if (DialogResult.Yes ==
MessageBox.Show("是否替换文件", "替换", MessageBoxButtons.YesNo))
saveMethod = false;
else
{
int i = 1;
while (File.Exists(path))
{
tbFileName.Text = fileName + i.ToString();
i++;
path = @"C:\Users\qin\Desktop\TeseCompile\" +
$"{tbFileName.Text}{labelFilePostfix.Text}";
saveMethod = true;
}
}
}
//保存
using (StreamWriter writer = new StreamWriter(path, saveMethod))
{
writer.Write(rtbScriptCode.Text);
MessageBox.Show($"文件:{tbFileName.Text}{labelFilePostfix.Text}保存成功!");
}
}
}
/// 导入文件
private void btnImportCode_Click(object sender, EventArgs e)
{
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Multiselect = true;
fileDialog.Title = "请选择文件";
fileDialog.Filter = "文本文件(*.txt)|*.txt; | 所有文件(*.*)|*.*";
if (fileDialog.ShowDialog() == DialogResult.OK)
{
rtbScriptCode.Text = "";
string file = fileDialog.FileName;
string fileName = fileDialog.SafeFileName;
tbFileName.Text = fileName.Substring(0, fileName.Length - ".txt".Length);
using (StreamReader read = new StreamReader(file))
{
string line = "";
while ((line = read.ReadLine()) != null)
{
rtbScriptCode.AppendText(line + "\r\n");
}
}
}
rtbScriptCode.SelectionLength = rtbScriptCode.Text.Length;
CompilerEffect();
}
3、运行效果
代码导入
运行效果
4、说明
2023-06-04
程序的不完善:
1、文本发生变化的重绘滚动(闪烁)问题。
程序中,使用RichTextBox控件编辑代码,每键入一个字符,都会触发文本变化事件,而关键字高亮显示是在文本发生变化后重绘的,所以会出现编写代码时存在闪烁问题。
测试发现如果不是导入的代码,不会发生闪烁问题(测试输入十行)。 测试编译时文本高亮显示无问题。
2、光标位置显示问题。
程序中,在导入代码后开始编辑,会发生类似滚动的现象(跟鼠标滚动一样)。 光标(焦点)跑位已解决。
3、关键字高亮显示后,直接在后面输入文字格式问题。
关键字后面的文本格式会跟关键字一样。
结语
既是分享,也是备份。
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。
如果有任何疑问或需要进一步的帮助,欢迎随时留言。
也可以加入微信公众号 [编程笔记in] 社区,与其他热爱技术的同行一起交流心得,共同成长!欢迎大家留言学习!