如何将WPF制作的编程画板改写为长尾关键词?

2026-03-27 00:061阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2649个文字,预计阅读时间需要11分钟。

如何将WPF制作的编程画板改写为长尾关键词?

目录+效果图+本次扩展的主要内容+可编程模块的实现原理+代码编辑模块的实现+代码编辑模块的编译与测试+WPF打印控制台数据+动态编译模块的输入输出自动生成+效果图

目录
  • 先上一张效果动图
  • 本次扩展的主要内容
    • 可编程模块的实现原理
    • 代码编辑模块的实现
    • 代码编辑模块的编译与测试
    • WPF打印控制台数据
    • 动态编译模块的输入输出自动生成

先上一张效果动图

同样老规矩,先上源码地址:gitee.com/akwkevin/aistudio.-wpf.-diagram

简单使用,自定义一个text模块的代码如下

Code = @"using System; namespace AIStudio.Wpf.CSharpScript {     public class Writer     {            public string StringValue{ get; set;} = ""Welcome to AIStudio.Wpf.Diagram"";         public string Execute()         {             return StringValue;         }     } }";

是不是很简单。

本次扩展的主要内容

1.可编程模块,使用C#语言。

2.控制台打印控件,可以打印程序中的Console.WriteLine数据

3.为了便于大家使用,写了一个Box工厂分配Box的数据流向效果图。

可编程模块的实现原理

使用Microsoft.CodeAnalysis.CSharp.Scripting对代码进行编译,生成Assembly,然后对Assembly反射获得对象,对象内部固定有一个Execute方法,每次扫描的时候执行即可。

1.编译使用的Using,必须添加引用集,为了省事,把整个程序的Reference都放入进行编译,获得引用的核心代码如下:

var references = AppDomain.CurrentDomain.GetAssemblies().Where(p => !p.IsDynamic && !string.IsNullOrEmpty(p.Location)).Select(x => MetadataReference.CreateFromFile(x.Location)).ToList(); //Costura.Fody压缩后,无Location,读取资源文件中的reference foreach (var assemblyEmbedded in AppDomain.CurrentDomain.GetAssemblies().Where(p => !p.IsDynamic && string.IsNullOrEmpty(p.Location))) {     using (var stream = Assembly.GetEntryAssembly().GetManifestResourceStream($"costura.{assemblyEmbedded.GetName().Name.ToLowerInvariant()}.dll.compressed"))     {         if (stream != null)         {             using (var compressStream = new DeflateStream(stream, CompressionMode.Decompress))             {                 var memStream = new MemoryStream();                 CopyTo(compressStream, memStream);                 memStream.Position = 0;                 references.Add(MetadataReference.CreateFromStream(memStream));             }         }     } }

2.动态编译的代码的核心代码如下:

public static Assembly GenerateAssemblyFromCode(string code, out string message) {     Assembly assembly = null;     message = "";     // 丛代码中转换表达式树     SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);     // 随机程序集名称     string assemblyName = Path.GetRandomFileName();     // 引用     // 创建编译对象     CSharpCompilation compilation = CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, References, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));     using (var ms = new MemoryStream())     {         // 将编译好的IL代码放入内存流         EmitResult result = compilation.Emit(ms);         // 编译失败,提示         if (!result.Success)         {             IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>                         diagnostic.IsWarningAsError ||                         diagnostic.Severity == DiagnosticSeverity.Error).ToList();             foreach (Diagnostic diagnostic in failures)             {                 message += $"{diagnostic.Id}: {diagnostic.GetMessage()}";                 Console.WriteLine(message);             }         }         else         {             // 编译成功,从内存中加载编译好的程序集             ms.Seek(0, SeekOrigin.Begin);             assembly = Assembly.Load(ms.ToArray());         }     }     return assembly; }

3.获得编译后的程序集,以及执行。

// 反射获取程序集中 的类 Type type = assembly.GetTypes().FirstOrDefault(p => p.FullName.StartsWith("AIStudio.Wpf"));   //assembly.GetType("AIStudio.Wpf.CSharpScript.Write"); // 创建该类的实例 object obj = Activator.CreateInstance(type); // 通过反射方式调用类中的方法。 var result = type.InvokeMember("Execute",     BindingFlags.Default | BindingFlags.InvokeMethod,     null,     obj,     new object[] { });

代码编辑模块的实现

选择AvalonEdit控件,另外为了使用VS2019_Dark的黑色皮肤,引用官方Demo中的HL和TextEditlib实现自定义换肤。

官方Demo的换肤写的超级复杂,看不懂,但是我们只要理解换肤的核心部分就是动态资源字典,因此我简化下,改进后的核心换肤代码如下:

public class TextEditorThemeHelper {     static Dictionary<string, ResourceDictionary> ThemeDictionary = new Dictionary<string, ResourceDictionary>();     public static List<string> Themes = new List<string>() { "Dark", "Light", "TrueBlue", "VS2019_Dark" };     public static string CurrentTheme { get; set; }     static TextEditorThemeHelper()     {         var resource = new ResourceDictionary { Source = new Uri("/TextEditLib;component/Themes/LightBrushs.xaml", UriKind.RelativeOrAbsolute) };         ThemeDictionary.Add("Light", resource);         resource = new ResourceDictionary { Source = new Uri("/TextEditLib;component/Themes/DarkBrushs.xaml", UriKind.RelativeOrAbsolute) };         ThemeDictionary.Add("Dark", resource);         Application.Current.Resources.MergedDictionaries.Add(resource);     }     /// <summary>     /// 设置主题     /// </summary>     /// <param name="theme"></param>     public static void SetCurrentTheme(string theme)     {         OnAppThemeChanged(theme);//切换到VS2019_Dark         CurrentTheme = theme;     }     /// <summary>     /// Invoke this method to apply a change of theme to the content of the document     /// (eg: Adjust the highlighting colors when changing from "Dark" to "Light"     ///      WITH current text document loaded.)     /// </summary>     internal static void OnAppThemeChanged(string theme)     {         ThemedHighlightingManager.Instance.SetCurrentTheme(theme);         if (ThemeDictionary.ContainsKey(theme))         {             foreach (var key in ThemeDictionary[theme].Keys)             {                 ApplyToDynamicResource(key, ThemeDictionary[theme][key]);             }         }         // Does this highlighting definition have an associated highlighting theme?         else if (ThemedHighlightingManager.Instance.CurrentTheme.HlTheme != null)         {             // A highlighting theme with GlobalStyles?             // Apply these styles to the resource keys of the editor             foreach (var item in ThemedHighlightingManager.Instance.CurrentTheme.HlTheme.GlobalStyles)             {                 switch (item.TypeName)                 {                     case "DefaultStyle":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorBackground, item.backgroundcolor);                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorForeground, item.foregroundcolor);                         break;                     case "CurrentLineBackground":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorCurrentLineBackgroundBrushKey, item.backgroundcolor);                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorCurrentLineBorderBrushKey, item.bordercolor);                         break;                     case "LineNumbersForeground":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorLineNumbersForeground, item.foregroundcolor);                         break;                     case "Selection":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorSelectionBrush, item.backgroundcolor);                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorSelectionBorder, item.bordercolor);                         break;                     case "Hyperlink":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorLinkTextBackgroundBrush, item.backgroundcolor);                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorLinkTextForegroundBrush, item.foregroundcolor);                         break;                     case "NonPrintableCharacter":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorNonPrintableCharacterBrush, item.foregroundcolor);                         break;                     default:                         throw new System.ArgumentOutOfRangeException("GlobalStyle named '{0}' is not supported.", item.TypeName);                 }             }         }     }     /// <summary>     /// Re-define an existing <seealso cref="SolidColorBrush"/> and backup the originial color     /// as it was before the application of the custom coloring.     /// </summary>     /// <param name="key"></param>     /// <param name="newColor"></param>     private static void ApplyToDynamicResource(ComponentResourceKey key, Color? newColor)     {         if (Application.Current.Resources[key] == null || newColor == null)             return;         // Re-coloring works with SolidColorBrushs linked as DynamicResource         if (Application.Current.Resources[key] is SolidColorBrush)         {             //backupDynResources.Add(resourceName);             var newColorBrush = new SolidColorBrush((Color)newColor);             newColorBrush.Freeze();             Application.Current.Resources[key] = newColorBrush;         }     }     private static void ApplyToDynamicResource(object key, object newValue)     {         if (Application.Current.Resources[key] == null || newValue == null)             return;         Application.Current.Resources[key] = newValue;     } }

使用方法:

TextEditorThemeHelper.SetCurrentTheme("VS2019_Dark");

或者 TextEditorThemeHelper.SetCurrentTheme("TrueBlue");

或者 TextEditorThemeHelper.SetCurrentTheme("Dark");

或者 TextEditorThemeHelper.SetCurrentTheme("Light");

是不是超级简单。

代码编辑模块的编译与测试

WPF打印控制台数据

///控制台打印方法支持切换运行输出方法Console.SetOut,核心代码如下: public class ConsoleWriter : TextWriter {     private readonly Action<string> _Write;     private readonly Action<string> _WriteLine;     private readonly Action<string, string, string, int> _WriteCallerInfo;     public ConsoleWriter()     {     }     /// <summary>     /// Console 输出重定向     /// </summary>     /// <param name="write">日志方法委托(针对于 Write)</param>     /// <param name="writeLine">日志方法委托(针对于 WriteLine)</param>     public ConsoleWriter(Action<string> write, Action<string> writeLine, Action<string, string, string, int> writeCallerInfo)     {         _Write = write;         _WriteLine = writeLine?? write;         _WriteCallerInfo = writeCallerInfo;     }     /// <summary>     /// Console 输出重定向     /// </summary>     /// <param name="write">日志方法委托(针对于 Write)</param>     /// <param name="writeLine">日志方法委托(针对于 WriteLine)</param>     public ConsoleWriter(Action<string> write, Action<string> writeLine)     {         _Write = write;         _WriteLine = writeLine;     }     /// <summary>     /// Console 输出重定向     /// </summary>     /// <param name="write">日志方法委托</param>     public ConsoleWriter(Action<string> write)     {         _Write = write;         _WriteLine = write;     }     /// <summary>     /// Console 输出重定向(带调用方信息)     /// </summary>     /// <param name="write">日志方法委托(后三个参数为 CallerFilePath、CallerMemberName、CallerLineNumber)</param>     public ConsoleWriter(Action<string, string, string, int> write)     {         _WriteCallerInfo = write;     }     /// <summary>     /// 使用 UTF-16 避免不必要的编码转换     /// </summary>     public override Encoding Encoding => Encoding.Unicode;     /// <summary>     /// 最低限度需要重写的方法     /// </summary>     /// <param name="value">消息</param>     public override void Write(string value)     {         if (_WriteCallerInfo != null)         {             WriteWithCallerInfo(value);             return;         }         _Write(value);     }     /// <summary>     /// 为提高效率直接处理一行的输出     /// </summary>     /// <param name="value">消息</param>     public override void WriteLine(string value)     {         if (_WriteCallerInfo != null)         {             WriteWithCallerInfo(value);             return;         }         _WriteLine(value);     }     /// <summary>     /// 带调用方信息进行写消息     /// </summary>     /// <param name="value">消息</param>     private void WriteWithCallerInfo(string value)     {         //3、System.Console.WriteLine -> 2、System.IO.TextWriter + SyncTextWriter.WriteLine -> 1、DotNet.Utilities.ConsoleHelper.ConsoleWriter.WriteLine -> 0、DotNet.Utilities.ConsoleHelper.ConsoleWriter.WriteWithCallerInfo         var callInfo = ClassHelper.GetMethodInfo(4);         _WriteCallerInfo(value, callInfo?.FileName, callInfo?.MethodName, callInfo?.LineNumber ?? 0);     }     public override void Close()     {         var standardOutput = new StreamWriter(Console.OpenStandardOutput());         standardOutput.AutoFlush = true;         Console.SetOut(standardOutput);         base.Close();     } }

使用:

如何将WPF制作的编程画板改写为长尾关键词?

ConsoleWriter ConsoleWriter = new ConsoleWriter(_write, _writeLine);

Console.SetOut(ConsoleWriter);

动态编译模块的输入输出自动生成

1.输入输出模块:public string Value{ get; set;}

2.输入模块:public string Value{private get; set;}

3.输出模块:public string Value{get;private set;}

4.与外部交互模块:private string Value{ get; set;} ,必须同名同属性。 核心代码如下:

public static Dictionary<string, List<PropertyInfo>> GetPropertyInfo(Type type) {     Dictionary<string, List<PropertyInfo>> puts = new Dictionary<string, List<PropertyInfo>>()     {         {"Input", new List<PropertyInfo>() },         {"Output", new List<PropertyInfo>() },         {"Input_Output", new List<PropertyInfo>() },         {"Inner", new List<PropertyInfo>() }     };     try     {         foreach (System.Reflection.PropertyInfo info in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))         {             if (info.CanRead && info.CanWrite)             {                 if (info.SetMethod.IsPublic && info.GetMethod.IsPublic)                 {                     puts["Input_Output"].Add(info);                 }                 else if (info.SetMethod.IsPublic)                 {                     puts["Input"].Add(info);                 }                 else if (info.GetMethod.IsPublic)                 {                     puts["Output"].Add(info);                 }             }             else if (info.CanRead)             {                 if (info.GetMethod.IsPublic)                 {                     puts["Output"].Add(info);                 }             }         }         foreach (System.Reflection.PropertyInfo info in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance))         {             if (info.CanRead)             {                 puts["Inner"].Add(info);             }         }     }     catch (Exception ex)     {     }     return puts; }

最后介绍一下Demo的实现

1#.Int整数模块,界面定义一个TextBox绑定Int模块的输入管脚。 2#.Box产生模块,如果内部数组为空,那么按照输入管脚的数量初始化一个容量为输入整数数量的数组(随机颜色与形状),然后把数据放到输出管脚,当数据被取走后,下一个数据再次放到输出管脚。 3#.Bool模块,为false的时候按照颜色进行分配,为true的时候按照形状进行分配。4#.Box分配模块,当输入管脚为空的时候,2#模块的输出可以移动到4#的输入管脚,移动时间为1s,移动完成后,清除2#模块的输出。同时把数据按照颜色或者形状分配到输出,同时把输入管脚清除。 按照颜色分配时: (1.如果颜色为红色,那么输出到1号 (2.如果颜色为橙色,那么输出到2号 (3.如果颜色为黄色,那么输出到3号 (4.如果颜色为绿色,那么输出到4号 (5.如果颜色为青色,那么输出到5号 (6.如果颜色为蓝色,那么输出到6号 (7.如果颜色为紫色,那么输出到7号 按照形状分配时: (1.如果形状为圆形,那么输出到1号 (2.如果形状为三角形,那么输出到2号 (3.如果形状为方形,那么输出到3号 (4.如果形状为菱形,那么输出到4号 (5.如果形状为梯形,那么输出到5号 (6.如果形状为五角星,那么输出到6号 (7.如果形状为六边形,那么输出到7号 6#.有两个红色|圆形收集器(7#,8#),按两个容器中的数量比较反馈,均匀分配到这两个收集器中。 9#,10#,11#,12#,13#,14#按照管脚取走数据即可。

以上就是基于WPF制作一个可编程画板的详细内容,更多关于WPF可编程画板的资料请关注自由互联其它相关文章!

标签:可编程

本文共计2649个文字,预计阅读时间需要11分钟。

如何将WPF制作的编程画板改写为长尾关键词?

目录+效果图+本次扩展的主要内容+可编程模块的实现原理+代码编辑模块的实现+代码编辑模块的编译与测试+WPF打印控制台数据+动态编译模块的输入输出自动生成+效果图

目录
  • 先上一张效果动图
  • 本次扩展的主要内容
    • 可编程模块的实现原理
    • 代码编辑模块的实现
    • 代码编辑模块的编译与测试
    • WPF打印控制台数据
    • 动态编译模块的输入输出自动生成

先上一张效果动图

同样老规矩,先上源码地址:gitee.com/akwkevin/aistudio.-wpf.-diagram

简单使用,自定义一个text模块的代码如下

Code = @"using System; namespace AIStudio.Wpf.CSharpScript {     public class Writer     {            public string StringValue{ get; set;} = ""Welcome to AIStudio.Wpf.Diagram"";         public string Execute()         {             return StringValue;         }     } }";

是不是很简单。

本次扩展的主要内容

1.可编程模块,使用C#语言。

2.控制台打印控件,可以打印程序中的Console.WriteLine数据

3.为了便于大家使用,写了一个Box工厂分配Box的数据流向效果图。

可编程模块的实现原理

使用Microsoft.CodeAnalysis.CSharp.Scripting对代码进行编译,生成Assembly,然后对Assembly反射获得对象,对象内部固定有一个Execute方法,每次扫描的时候执行即可。

1.编译使用的Using,必须添加引用集,为了省事,把整个程序的Reference都放入进行编译,获得引用的核心代码如下:

var references = AppDomain.CurrentDomain.GetAssemblies().Where(p => !p.IsDynamic && !string.IsNullOrEmpty(p.Location)).Select(x => MetadataReference.CreateFromFile(x.Location)).ToList(); //Costura.Fody压缩后,无Location,读取资源文件中的reference foreach (var assemblyEmbedded in AppDomain.CurrentDomain.GetAssemblies().Where(p => !p.IsDynamic && string.IsNullOrEmpty(p.Location))) {     using (var stream = Assembly.GetEntryAssembly().GetManifestResourceStream($"costura.{assemblyEmbedded.GetName().Name.ToLowerInvariant()}.dll.compressed"))     {         if (stream != null)         {             using (var compressStream = new DeflateStream(stream, CompressionMode.Decompress))             {                 var memStream = new MemoryStream();                 CopyTo(compressStream, memStream);                 memStream.Position = 0;                 references.Add(MetadataReference.CreateFromStream(memStream));             }         }     } }

2.动态编译的代码的核心代码如下:

public static Assembly GenerateAssemblyFromCode(string code, out string message) {     Assembly assembly = null;     message = "";     // 丛代码中转换表达式树     SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);     // 随机程序集名称     string assemblyName = Path.GetRandomFileName();     // 引用     // 创建编译对象     CSharpCompilation compilation = CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, References, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));     using (var ms = new MemoryStream())     {         // 将编译好的IL代码放入内存流         EmitResult result = compilation.Emit(ms);         // 编译失败,提示         if (!result.Success)         {             IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>                         diagnostic.IsWarningAsError ||                         diagnostic.Severity == DiagnosticSeverity.Error).ToList();             foreach (Diagnostic diagnostic in failures)             {                 message += $"{diagnostic.Id}: {diagnostic.GetMessage()}";                 Console.WriteLine(message);             }         }         else         {             // 编译成功,从内存中加载编译好的程序集             ms.Seek(0, SeekOrigin.Begin);             assembly = Assembly.Load(ms.ToArray());         }     }     return assembly; }

3.获得编译后的程序集,以及执行。

// 反射获取程序集中 的类 Type type = assembly.GetTypes().FirstOrDefault(p => p.FullName.StartsWith("AIStudio.Wpf"));   //assembly.GetType("AIStudio.Wpf.CSharpScript.Write"); // 创建该类的实例 object obj = Activator.CreateInstance(type); // 通过反射方式调用类中的方法。 var result = type.InvokeMember("Execute",     BindingFlags.Default | BindingFlags.InvokeMethod,     null,     obj,     new object[] { });

代码编辑模块的实现

选择AvalonEdit控件,另外为了使用VS2019_Dark的黑色皮肤,引用官方Demo中的HL和TextEditlib实现自定义换肤。

官方Demo的换肤写的超级复杂,看不懂,但是我们只要理解换肤的核心部分就是动态资源字典,因此我简化下,改进后的核心换肤代码如下:

public class TextEditorThemeHelper {     static Dictionary<string, ResourceDictionary> ThemeDictionary = new Dictionary<string, ResourceDictionary>();     public static List<string> Themes = new List<string>() { "Dark", "Light", "TrueBlue", "VS2019_Dark" };     public static string CurrentTheme { get; set; }     static TextEditorThemeHelper()     {         var resource = new ResourceDictionary { Source = new Uri("/TextEditLib;component/Themes/LightBrushs.xaml", UriKind.RelativeOrAbsolute) };         ThemeDictionary.Add("Light", resource);         resource = new ResourceDictionary { Source = new Uri("/TextEditLib;component/Themes/DarkBrushs.xaml", UriKind.RelativeOrAbsolute) };         ThemeDictionary.Add("Dark", resource);         Application.Current.Resources.MergedDictionaries.Add(resource);     }     /// <summary>     /// 设置主题     /// </summary>     /// <param name="theme"></param>     public static void SetCurrentTheme(string theme)     {         OnAppThemeChanged(theme);//切换到VS2019_Dark         CurrentTheme = theme;     }     /// <summary>     /// Invoke this method to apply a change of theme to the content of the document     /// (eg: Adjust the highlighting colors when changing from "Dark" to "Light"     ///      WITH current text document loaded.)     /// </summary>     internal static void OnAppThemeChanged(string theme)     {         ThemedHighlightingManager.Instance.SetCurrentTheme(theme);         if (ThemeDictionary.ContainsKey(theme))         {             foreach (var key in ThemeDictionary[theme].Keys)             {                 ApplyToDynamicResource(key, ThemeDictionary[theme][key]);             }         }         // Does this highlighting definition have an associated highlighting theme?         else if (ThemedHighlightingManager.Instance.CurrentTheme.HlTheme != null)         {             // A highlighting theme with GlobalStyles?             // Apply these styles to the resource keys of the editor             foreach (var item in ThemedHighlightingManager.Instance.CurrentTheme.HlTheme.GlobalStyles)             {                 switch (item.TypeName)                 {                     case "DefaultStyle":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorBackground, item.backgroundcolor);                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorForeground, item.foregroundcolor);                         break;                     case "CurrentLineBackground":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorCurrentLineBackgroundBrushKey, item.backgroundcolor);                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorCurrentLineBorderBrushKey, item.bordercolor);                         break;                     case "LineNumbersForeground":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorLineNumbersForeground, item.foregroundcolor);                         break;                     case "Selection":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorSelectionBrush, item.backgroundcolor);                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorSelectionBorder, item.bordercolor);                         break;                     case "Hyperlink":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorLinkTextBackgroundBrush, item.backgroundcolor);                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorLinkTextForegroundBrush, item.foregroundcolor);                         break;                     case "NonPrintableCharacter":                         ApplyToDynamicResource(TextEditLib.Themes.ResourceKeys.EditorNonPrintableCharacterBrush, item.foregroundcolor);                         break;                     default:                         throw new System.ArgumentOutOfRangeException("GlobalStyle named '{0}' is not supported.", item.TypeName);                 }             }         }     }     /// <summary>     /// Re-define an existing <seealso cref="SolidColorBrush"/> and backup the originial color     /// as it was before the application of the custom coloring.     /// </summary>     /// <param name="key"></param>     /// <param name="newColor"></param>     private static void ApplyToDynamicResource(ComponentResourceKey key, Color? newColor)     {         if (Application.Current.Resources[key] == null || newColor == null)             return;         // Re-coloring works with SolidColorBrushs linked as DynamicResource         if (Application.Current.Resources[key] is SolidColorBrush)         {             //backupDynResources.Add(resourceName);             var newColorBrush = new SolidColorBrush((Color)newColor);             newColorBrush.Freeze();             Application.Current.Resources[key] = newColorBrush;         }     }     private static void ApplyToDynamicResource(object key, object newValue)     {         if (Application.Current.Resources[key] == null || newValue == null)             return;         Application.Current.Resources[key] = newValue;     } }

使用方法:

TextEditorThemeHelper.SetCurrentTheme("VS2019_Dark");

或者 TextEditorThemeHelper.SetCurrentTheme("TrueBlue");

或者 TextEditorThemeHelper.SetCurrentTheme("Dark");

或者 TextEditorThemeHelper.SetCurrentTheme("Light");

是不是超级简单。

代码编辑模块的编译与测试

WPF打印控制台数据

///控制台打印方法支持切换运行输出方法Console.SetOut,核心代码如下: public class ConsoleWriter : TextWriter {     private readonly Action<string> _Write;     private readonly Action<string> _WriteLine;     private readonly Action<string, string, string, int> _WriteCallerInfo;     public ConsoleWriter()     {     }     /// <summary>     /// Console 输出重定向     /// </summary>     /// <param name="write">日志方法委托(针对于 Write)</param>     /// <param name="writeLine">日志方法委托(针对于 WriteLine)</param>     public ConsoleWriter(Action<string> write, Action<string> writeLine, Action<string, string, string, int> writeCallerInfo)     {         _Write = write;         _WriteLine = writeLine?? write;         _WriteCallerInfo = writeCallerInfo;     }     /// <summary>     /// Console 输出重定向     /// </summary>     /// <param name="write">日志方法委托(针对于 Write)</param>     /// <param name="writeLine">日志方法委托(针对于 WriteLine)</param>     public ConsoleWriter(Action<string> write, Action<string> writeLine)     {         _Write = write;         _WriteLine = writeLine;     }     /// <summary>     /// Console 输出重定向     /// </summary>     /// <param name="write">日志方法委托</param>     public ConsoleWriter(Action<string> write)     {         _Write = write;         _WriteLine = write;     }     /// <summary>     /// Console 输出重定向(带调用方信息)     /// </summary>     /// <param name="write">日志方法委托(后三个参数为 CallerFilePath、CallerMemberName、CallerLineNumber)</param>     public ConsoleWriter(Action<string, string, string, int> write)     {         _WriteCallerInfo = write;     }     /// <summary>     /// 使用 UTF-16 避免不必要的编码转换     /// </summary>     public override Encoding Encoding => Encoding.Unicode;     /// <summary>     /// 最低限度需要重写的方法     /// </summary>     /// <param name="value">消息</param>     public override void Write(string value)     {         if (_WriteCallerInfo != null)         {             WriteWithCallerInfo(value);             return;         }         _Write(value);     }     /// <summary>     /// 为提高效率直接处理一行的输出     /// </summary>     /// <param name="value">消息</param>     public override void WriteLine(string value)     {         if (_WriteCallerInfo != null)         {             WriteWithCallerInfo(value);             return;         }         _WriteLine(value);     }     /// <summary>     /// 带调用方信息进行写消息     /// </summary>     /// <param name="value">消息</param>     private void WriteWithCallerInfo(string value)     {         //3、System.Console.WriteLine -> 2、System.IO.TextWriter + SyncTextWriter.WriteLine -> 1、DotNet.Utilities.ConsoleHelper.ConsoleWriter.WriteLine -> 0、DotNet.Utilities.ConsoleHelper.ConsoleWriter.WriteWithCallerInfo         var callInfo = ClassHelper.GetMethodInfo(4);         _WriteCallerInfo(value, callInfo?.FileName, callInfo?.MethodName, callInfo?.LineNumber ?? 0);     }     public override void Close()     {         var standardOutput = new StreamWriter(Console.OpenStandardOutput());         standardOutput.AutoFlush = true;         Console.SetOut(standardOutput);         base.Close();     } }

使用:

如何将WPF制作的编程画板改写为长尾关键词?

ConsoleWriter ConsoleWriter = new ConsoleWriter(_write, _writeLine);

Console.SetOut(ConsoleWriter);

动态编译模块的输入输出自动生成

1.输入输出模块:public string Value{ get; set;}

2.输入模块:public string Value{private get; set;}

3.输出模块:public string Value{get;private set;}

4.与外部交互模块:private string Value{ get; set;} ,必须同名同属性。 核心代码如下:

public static Dictionary<string, List<PropertyInfo>> GetPropertyInfo(Type type) {     Dictionary<string, List<PropertyInfo>> puts = new Dictionary<string, List<PropertyInfo>>()     {         {"Input", new List<PropertyInfo>() },         {"Output", new List<PropertyInfo>() },         {"Input_Output", new List<PropertyInfo>() },         {"Inner", new List<PropertyInfo>() }     };     try     {         foreach (System.Reflection.PropertyInfo info in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))         {             if (info.CanRead && info.CanWrite)             {                 if (info.SetMethod.IsPublic && info.GetMethod.IsPublic)                 {                     puts["Input_Output"].Add(info);                 }                 else if (info.SetMethod.IsPublic)                 {                     puts["Input"].Add(info);                 }                 else if (info.GetMethod.IsPublic)                 {                     puts["Output"].Add(info);                 }             }             else if (info.CanRead)             {                 if (info.GetMethod.IsPublic)                 {                     puts["Output"].Add(info);                 }             }         }         foreach (System.Reflection.PropertyInfo info in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance))         {             if (info.CanRead)             {                 puts["Inner"].Add(info);             }         }     }     catch (Exception ex)     {     }     return puts; }

最后介绍一下Demo的实现

1#.Int整数模块,界面定义一个TextBox绑定Int模块的输入管脚。 2#.Box产生模块,如果内部数组为空,那么按照输入管脚的数量初始化一个容量为输入整数数量的数组(随机颜色与形状),然后把数据放到输出管脚,当数据被取走后,下一个数据再次放到输出管脚。 3#.Bool模块,为false的时候按照颜色进行分配,为true的时候按照形状进行分配。4#.Box分配模块,当输入管脚为空的时候,2#模块的输出可以移动到4#的输入管脚,移动时间为1s,移动完成后,清除2#模块的输出。同时把数据按照颜色或者形状分配到输出,同时把输入管脚清除。 按照颜色分配时: (1.如果颜色为红色,那么输出到1号 (2.如果颜色为橙色,那么输出到2号 (3.如果颜色为黄色,那么输出到3号 (4.如果颜色为绿色,那么输出到4号 (5.如果颜色为青色,那么输出到5号 (6.如果颜色为蓝色,那么输出到6号 (7.如果颜色为紫色,那么输出到7号 按照形状分配时: (1.如果形状为圆形,那么输出到1号 (2.如果形状为三角形,那么输出到2号 (3.如果形状为方形,那么输出到3号 (4.如果形状为菱形,那么输出到4号 (5.如果形状为梯形,那么输出到5号 (6.如果形状为五角星,那么输出到6号 (7.如果形状为六边形,那么输出到7号 6#.有两个红色|圆形收集器(7#,8#),按两个容器中的数量比较反馈,均匀分配到这两个收集器中。 9#,10#,11#,12#,13#,14#按照管脚取走数据即可。

以上就是基于WPF制作一个可编程画板的详细内容,更多关于WPF可编程画板的资料请关注自由互联其它相关文章!

标签:可编程