- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在创建一个设计器界面并将控件加载到运行时。我在将控件反序列化/加载到运行时时遇到问题。
我尝试过的所有方法似乎都存在某种类型的问题。
发出面临的例子:
我在 git 上创建了一个示例项目:Surface Designer Test
主要代码片段:
从设计时开始序列化
private void LoadRuntime(int type)
{
var controls = surface.ComponentContainer.Components;
SerializationStore data = (SerializationStore)surface.
_designerSerializationService.Serialize(controls);
MemoryStream ms = new MemoryStream();
data.Save(ms);
SaveData.Data = ms.ToArray();
SaveData.LoadType = type;
new RuntimeForm().Show();
}
public object Serialize(System.Collections.ICollection objects)
{
ComponentSerializationService componentSerializationService =
_serviceProvider.GetService(typeof(ComponentSerializationService)) as
ComponentSerializationService;
SerializationStore returnObject = null;
using (SerializationStore serializationStore =
componentSerializationService.CreateStore())
{
foreach (object obj in objects)
{
if (obj is Control control)
{
componentSerializationService.SerializeAbsolute(serializationStore, obj);
}
returnObject = serializationStore;
}
}
return returnObject;
}
运行时反序列化
这是反射的尝试:
MemoryStream ms = new MemoryStream(SaveData.Data);
Designer d = new Designer();
var controls = d._designerSerializationService.Deserialize(ms);
ms.Close();
if (SaveData.LoadType == 1)
{
foreach (Control cont in controls)
{
var ts = Assembly.Load(cont.GetType().Assembly.FullName);
var o = ts.GetType(cont.GetType().FullName);
Control controlform = (Control)Activator.CreateInstance(o);
PropertyInfo[] controlProperties = cont.GetType().GetProperties();
foreach (PropertyInfo propInfo in controlProperties)
{
if (propInfo.CanWrite)
{
if (propInfo.Name != "Site" && propInfo.Name != WindowTarget")
{
try
{
var obj = propInfo.GetValue(cont, null);
propInfo.SetValue(controlform, obj, null);
}
catch { }
}
else { }
}
}
Controls.Add(controlform);
}
}
这是直接加载控件的尝试(仍然绑定(bind)到设计时):
MemoryStream ms = new MemoryStream(SaveData.Data);
Designer d = new Designer();
var controls = d._designerSerializationService.Deserialize(ms);
foreach (Control cont in controls)
Controls.Add(cont);
我觉得我错过了 System.ComponentModel.Design
中的一个概念框架。
我也不认为有必要为每个控件编写一个自定义序列化器,因为 Visual Studio 肯定已经有了这个序列化器,能够在 PropertyGrid
中更改它们的所有属性时序列化它们> 并在运行程序时加载它们。
我很想将设计器序列化到 .cs
文件中,但是如何实现呢?如何序列化控件/表单并将属性更改为像 VS 设计器一样的文件,我尝试并只找到了 xml 和二进制序列化器。我理想的解决方案是使用 CodeDom
构建一个 designer.cs
。
在设计时和运行时之间完成这种序列化的正确方法是什么?
最佳答案
假设您有 DesignSurface
将 Form
显示为设计器的根组件,并使用 CreateComponent
在运行时创建一些组件方法IDesignerHost
,这是我解决问题的方法:
IDesignerHost
的实例来自DesignSurface
DesignerSerializationManager
TypeCodeDomSerializer
的实例来自序列化管理器RootComponent
IDesignerHost
的CSharpCodeProvider
的实例GenerateCodeFromType
生成代码并传递序列化的根组件。您还可以稍微扩展示例并使用 ISelectionService
使用 PropertyGrid
获取有关所选组件的通知并在运行时更改属性:
在此示例中,我将展示如何在运行时托管 Windows 窗体设计器并设计包含一些控件和组件的窗体,并在运行时生成 C# 代码并运行生成的代码。
Please note: It's not a production code and it's just an example as a proof of concept.
创建 DesignSurface 并托管设计器
您可以像这样创 build 计图面:
DesignSurface designSurface;
private void Form1_Load(object sender, EventArgs e)
{
designSurface = new DesignSurface(typeof(Form));
var host = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost));
var root = (Form)host.RootComponent;
TypeDescriptor.GetProperties(root)["Name"].SetValue(root, "Form1");
root.Text = "Form1";
var button1 = (Button)host.CreateComponent(typeof(Button), "button1");
button1.Text = "button1";
button1.Location = new Point(8, 8);
root.Controls.Add(button1);
var timer1 = (Timer)host.CreateComponent(typeof(Timer), "timer1");
timer1.Interval = 2000;
var view = (Control)designSurface.View;
view.Dock = DockStyle.Fill;
view.BackColor = Color.White;
this.Controls.Add(view);
}
使用 TypeCodeDomSerializer 和 CSharpCodeProvider 生成 C# 代码
这就是我从设计界面生成代码的方式:
string GenerateCSFromDesigner(DesignSurface designSurface)
{
CodeTypeDeclaration type;
var host = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost));
var root = host.RootComponent;
var manager = new DesignerSerializationManager(host);
using (manager.CreateSession())
{
var serializer = (TypeCodeDomSerializer)manager.GetSerializer(root.GetType(),
typeof(TypeCodeDomSerializer));
type = serializer.Serialize(manager, root, host.Container.Components);
type.IsPartial = true;
type.Members.OfType<CodeConstructor>()
.FirstOrDefault().Attributes = MemberAttributes.Public;
}
var builder = new StringBuilder();
CodeGeneratorOptions option = new CodeGeneratorOptions();
option.BracingStyle = "C";
option.BlankLinesBetweenMembers = false;
using (var writer = new StringWriter(builder, CultureInfo.InvariantCulture))
{
using (var codeDomProvider = new CSharpCodeProvider())
{
codeDomProvider.GenerateCodeFromType(type, writer, option);
}
return builder.ToString();
}
}
例如:
var code = GenerateCSFromDesigner(designSurface);
通过 CSharpCodeProvider 运行代码
然后运行它:
void Run(string code, string formName)
{
var csc = new CSharpCodeProvider();
var parameters = new CompilerParameters(new[] {
"mscorlib.dll",
"System.Windows.Forms.dll",
"System.dll",
"System.Drawing.dll",
"System.Core.dll",
"Microsoft.CSharp.dll"});
parameters.GenerateExecutable = true;
code = $@"
{code}
public class Program
{{
[System.STAThread]
static void Main()
{{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
System.Windows.Forms.Application.Run(new {formName}());
}}
}}";
var results = csc.CompileAssemblyFromSource(parameters, code);
if (!results.Errors.HasErrors)
{
System.Diagnostics.Process.Start(results.CompiledAssembly.CodeBase);
}
else
{
var errors = string.Join(Environment.NewLine,
results.Errors.Cast<CompilerError>().Select(x => x.ErrorText));
MessageBox.Show(errors);
}
}
例如:
Run(GenerateCSFromDesigner(designSurface), "Form1");
关于c# - 托管 Windows 窗体设计器 - 在运行时序列化设计器并生成 C# 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59529839/
对于一个科学实验,我写了一个turtle.py ,它会打开一个 800x480 的窗口并绘制一个缓慢增长的黑点。 turtle.py以 C:\Users\kaza>python C:\Users\ka
我开发了一个 swing 应用程序,但每次运行应用程序时都会打开一个新窗口。我希望如果一个窗口已经打开,则其他窗口不允许打开。 最佳答案 Here是一个 Java 单一应用实例的例子: A singl
有没有办法检测主进程中 Electron 的结构? process.platform 似乎也在 x64 机器上返回 win32,我没有在文档中找到任何获取架构的选项。 最佳答案 你试过 process
public short[] HanningWindow(short[] signal_in ,int pos ,int size) { for (int i= pos; i < pos+si
我有一个具有这些属性的 Electron 窗口: mainWindow = new BrowserWindow({ width: 800, height: 600, title: "Aqu
我有一个 Ubuntu 工作站,我正在尝试引导一个 Windows 节点。 Windows 节点在端口 2222 上打开了 ssh。我一直在关注 http://docs.opscode.com/plu
我是一名优秀的程序员,十分优秀!