锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / C#界面控件开源英语_C#界面控件编程心得翻译 / .NET窗体皮肤系统
服务方向
人工智能数据处理
人工智能培训
kaldi数据准备
小语种语音识别
语音识别标注
语音识别系统
语音识别转文字
kaldi开发技术服务
软件开发
运动控制卡上位机
机械加工软件
软件开发培训
Java 安卓移动开发
VC++
C#软件
汇编和破解
驱动开发
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft

锐英源精品开源心得,转载请注明:“锐英源www.wisestudy.cn,孙老师作品,电话13803810136。”需要全文内容也请联系孙老师。

.NET窗体皮肤系统

Introduction

Ever since I started developing Windows Forms applications, I always missed the possibility to have different user interfaces for the same application. I've considered several techniques ranging from image-based skinning to creating a custom window framework (e.g., Mozilla's XUL). Image based skinning isn't very dynamic, and creating a framework would require a lot of development.

In my search for dynamic skinning, I've come up with the idea of using .NET libraries to provide the necessary forms. In this article, I'll go into the details of my solution.自从我开始开发Windows窗体应用程序以来,我总是错过了为同一个应用程序提供不同用户界面的可能性。我考虑过几种技术,从基于图像的蒙皮到创建自定义窗口框架(例如,Mozilla的XUL)。基于图像的皮肤不是很动态,创建框架需要大量的开发。

在我寻找动态皮肤时,我想出了使用.NET库来提供必要形式的想法。在本文中,我将详细介绍我的解决方案。

Using the code

The following figure briefly illustrates how GUISS works:下图简要说明了GUISS的工作原理:

Schematic1

We have three components: the parent application, the GUISS library, and the skin library. The order of processing is like this (mind that this is very simplified):

  • The parent application instantiates a new Forcepoint.GUISS.Skin class.
  • To load a Skin Library, Forcepoint.GUISS.Skin.LoadSkin(string fileName) is called.
  • The parent application creates a new instance of one of its classes that inherit FormParent.
  • The newly instantiated class is used as a parameter for Forcepoint.GUISS.Skin.CreateForm(FormParent formParent).
  • The GUISS library 'extracts' a FormWindow that matches the given FormParent and returns a fully functional FormWindow that has the same properties, methods etc., as a regular form.
  • GUISS checks if all the controls required by the FormParent are available on the FormWindow.
  • GUISS hooks all the necessary events to the controls.
  • To get a differently skinned FormWindow, load a different skin library.

Everything you need to use GUISS can be found in the Forcepoint.GUISS namespace.

我们有三个组件:父应用程序,GUISS库和皮肤库。处理的顺序是这样的(注意这是非常简化的说明):

  • 父应用程序实例化一个新Forcepoint.GUISS.Skin类。
  • 要加载外观库,请调用Forcepoint.GUISS.Skin.LoadSkin(string fileName)。
  • 父应用程序创建新实例,其继承的其中一个类是FormParent。
  • 新实例化的类用作如下调用的参数:Forcepoint.GUISS.Skin.CreateForm(FormParent formParent)。
  • GUISS库“提取” FormWindow与给定的匹配,FormParent并返回FormWindow具有相同属性,方法等的完整功能,作为常规形式。
  • GUISS检查是否FormParent需要的所有控件都可用FormWindow。
  • GUISS将所有必要的事件挂钩到控件。
  • 要获得不同的皮肤FormWindow,请加载不同的皮肤库。

您可以在Forcepoint.GUISS命名空间中找到使用GUISS所需的一切。

Creating the parent application创建父应用程序

In short, parent applications (which I will often abbreviate to "PA") contain the logical code needed to run the application. Skin libraries are the exact opposites, they just contain the forms needed by the parent application.

Instead of having regular forms in your solution, you'll have one or more FormParent classes. These are just standard classes, but they inherit from Forcepoint.GUISS.FormParent. The FormParent abstract class has several properties/functions that you must override. These are:

  • string FormName
  • Dictionary<string,> DeclareRequiredControls()
  • List<subscribedevent> DeclareEventsToSubscribeTo()
  • Dictionary<string,> DeclareWatchedObjects()

In code, it will look like this:

简而言之,父应用程序(我通常将其缩写为“PA”)包含运行应用程序所需的逻辑代码。皮肤库是完全相反的,它们只包含父应用程序所需的表单。

您将拥有一个或多个FormParent类,而不是在解决方案中使用常规表单。这些只是标准类,但它们继承自Forcepoint.GUISS.FormParent。该FormParent抽象类有几种特性/功能,你必须重写。这些是:

  • string FormName
  • Dictionary<string,> DeclareRequiredControls()
  • List<subscribedevent> DeclareEventsToSubscribeTo()
  • Dictionary<string,> DeclareWatchedObjects()

在代码中,它看起来像这样:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

using Forcepoint.GUISS;

namespace ParentApplication
{
public class MainForm : FormParent
{
public override string FormName
{
get { return "MainForm"; }
}

public override Dictionary<string,> DeclareRequiredControls()
{
Dictionary<string,> tmp = new Dictionary<string,>();

tmp.Add("rtb_Text", typeof(RichTextBox));

tmp.Add("btn_Open", null);
tmp.Add("btn_Save", null);
tmp.Add("btn_SaveAs", null);

return tmp;
}
public override List<subscribedevent> DeclareEventsToSubscribeTo()
{
List<subscribedevent> tmp = new List<subscribedevent>();

tmp.Add(new SubscribedEvent(null, "Load",
new Subscriber.GenericEventHandler(MainForm_Load)));

//The btn_..._Click's aren't shown in this code block.
tmp.Add(new SubscribedEvent("btn_Open", "Click",
new Subscriber.GenericEventHandler(btn_Open_Click)));
tmp.Add(new SubscribedEvent("btn_Save", "Click",
new Subscriber.GenericEventHandler(btn_Save_Click)));
tmp.Add(new SubscribedEvent("btn_SaveAs", "Click",
new Subscriber.GenericEventHandler(btn_SaveAs_Click)));

return tmp;
}
public override Dictionary<string,> DeclareWatchedObjects()
{
//Will be discussed later in this article.
}

...

}
}

So, how do the FormParent and the FormWindow interact? Take a look at the schema above the code block. The parent application requests a FormWindow by calling the Skin.CreateForm(FormParent formParent)function. Once the parent application calls this function, the GUISS library calls the overridden functions you've just seen in the code block above.

First, GUISS checks if the FormParent's FormName property is the same as that of the FormWindow. After that, GUISS verifies if all the Controls required by the FormParent (DeclareRequiredControls()) are on the FormWindow. If not, an error is thrown. Once that's done, GUISS hooks the appropriate events to all controls (DeclareEventsToSubscribeTo()). Finally, GUISS calls DeclareWatchedObjects(), which we will discuss later in this article.

If all went well, Skin.CreateForm(FormParent formParent) will return a FormWindow. This is a class that inherits System.Windows.Forms.Form, so it behaves the same.

那么,FormParent和FormWindow如何互动?看一下代码块上方的模式。父应用程序通过调用该Skin.CreateForm(FormParent formParent)函数来请求FormWindow 。一旦父应用程序调用此函数,GUISS库将调用您刚才在上面的代码块中看到的重写函数。

首先,GUISS会检查FormParent的FormName属性是相同的FormWindow。之后,GUISS将验证FormParent(DeclareRequiredControls())所需的所有控件是否都在FormWindow。如果不是,则抛出错误。完成后,GUISS将适当的事件挂钩到所有控件(DeclareEventsToSubscribeTo())。最后,GUISS调用DeclareWatchedObjects(),我们将在本文后面讨论。

如果一切顺利,Skin.CreateForm(FormParent formParent)将返回一个FormWindow。这是一个继承的类System.Windows.Forms.Form,因此它的行为相同。

Creating a skin library

Skin libraries consist of classes that inherit from FormWindow, which in turn inherit Form. Therefore, you can use the Visual Studio designer. You don't need to override anything, the FormWindow class only adds certain functions and methods you can (and should) use. This is an example of how the class would look like:皮肤库由继承的类组成,而这些类FormWindow又继承Form。因此,您可以使用Visual Studio设计器。您不需要覆盖任何内容,FormWindow该类仅添加您可以(并且应该)使用的某些函数和方法。这是类的外观示例:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using Forcepoint.GUISS;

namespace TextEditor.DarkSkin
{
public partial class MainForm : FormWindow
{
public MainForm()
{
InitializeComponent();

RegisterControl(rtb_Text.Name, rtb_Text);
RegisterControl("btn_Open", btn_Open);
RegisterControl("btn_Save", btn_Save);
RegisterControl("btn_SaveAs", btn_SaveAs);
}

private void MainForm_Load(object sender, EventArgs e)
{
//This will be discussed later on in this article.
this.WatchedObjects["current_Text"].OnSet +=
new EventHandler<watchedobjectseteventargs>(current_Text_OnSet);
this.WatchedObjects["current_Text"].OnGet +=
new EventHandler<watchedobjectgeteventargs>(current_Text_OnGet);
}

...

}
}

How they interact

The FormWindow must 'register' the controls required by the FormParent. This can be done through the RegisterControl() and RegisterAllControls() methods. One or both of these methods must be called right after InitializeComponent() in the FormWindow's constructor.

For example, the FormParent requires the btn_SaveAs control on the FormWindow. It also requires it to be a RichTextBox. The FormWindow must register this control by using RegisterControl() or RegisterAllControls(). The FormParent class can access these controls via the FormWindow.GetRegisteredControl() function:在FormWindow必须“注册”FormParent所需的控件。这可以通过RegisterControl()和RegisterAllControls()方法完成。FormWindow构造函数中InitializeComponent()后面必须调用其中一个或两个方法。

例如,FormParent需要btn_SaveAs控件权FormWindow。它还要求它是一个RichTextBox。在FormWindow必须注册使用该控件RegisterControl()或RegisterAllControls()。该FormParent班可通过访问这些控件FormWindow.GetRegisteredControl()功能:

string ExampleString =
    ((RichTextBox)this.FormWindow.GetRegisteredControl(
   "btn_SaveAs").ControlObject).Text;

You don't always know what type the control is when you use GetRegisteredControl. If this is the case, you can use a WatchedObject.使用时,您并不总是知道控件的类型GetRegisteredControl。如果是这种情况,您可以使用WatchedObject。

this.WatchedObjects["current_Text"].OnSet +=
     new EventHandler<watchedobjectseteventargs>(current_Text_OnSet);
  this.WatchedObjects["current_Text"].OnGet +=
     new EventHandler<watchedobjectgeteventargs>(current_Text_OnGet);

When WatchedObject["current_Text"].Object is get or set, the appropriate events are called. Both the parent application and the skin library can set these events.

For example (these methods are both in the skin library):何时WatchedObject["current_Text"].Object获取或设置,将调用相应的事件。父应用程序和皮肤库都可以设置这些事件。

例如(这些方法都在皮肤库中):

void current_Text_OnSet(object sender, WatchedObjectSetEventArgs e)
{
      this.rtb_Text.Text = e.NewValue.ToString();
}
void current_Text_OnGet(object sender, WatchedObjectGetEventArgs e)
{
     e.ValueToReturn = this.rtb_Text.Text;
}

When the object is set (which is done by the parent application), the Text property of the rtb_Text control is set to the new value. Note that the parent application doesn't have to know anything about the control in the skin library. Now, when the object is gotten by the parent application, the skin library returns the Text property of the rtb_Text control.设置对象(由父应用程序完成)后,控件的Text属性将rtb_Text设置为新值。请注意,父应用程序不必了解皮肤库中的控件。现在,当父应用程序获取对象时,外观库将返回控件的Text属性rtb_Text。

Points of interest

FormWindow control registering

As mentioned previously, there are two methods used for registering controls. These are RegisterControl()and RegisterAllControls().

RegisterAllControls iterates recursively through all the controls. It does this by walking through FormWindow.Controls, FormWindow.Controls.Controls, FormWindow.Controls.Controls.Controlsetc. This works well for Panels and some other controls, but not for ToolStripMenuItem and alike. To resolve this problem, RegisterControl() comes in handy.

RegisterControl("ToolStripMenuItem_SaveAs", ToolStripMenuItem_SaveAs);
  //even easier:  
//RegisterControl(ToolStripMenuItem_SaveAs.Name, ToolStripMenuItem_SaveAs);

Security

The parent application requires certain security permissions to be set by the skin library. Take a look at the following code on how to get the permissions:

[STAThread]
static void Main()
{
...
Skin Skin = new Skin();
//Set the security checks.
Skin.SecurityChecks.Add(typeof(FileIOPermissionAttribute),
new SecurityCheckDelegate(SecurityCheck_FileIOPermission));

Skin.LoadSkin(Application.StartupPath + @"\Skins\" + sp.listBox1.Text);

Application.Run(Skin.CreateForm(new MainForm()));
}

private static bool SecurityCheck_FileIOPermission(object permissionAttribute)
{
//PermissionAttribute is an attribute in the Skin Library.

FileIOPermissionAttribute fiopa =
(FileIOPermissionAttribute)permissionAttribute;
//This basically means: Request Refusal
//for having Unrestricted access to the FileSystem.
//In other words: block all access.
if (fiopa.Action == SecurityAction.RequestRefuse && fiopa.Unrestricted == true)
return true;
else
return false;
}

The skin library sets security permissions at the bottom of the AssemblyInfo.cs file:

//This will fail the security check. Unrestricted must be true to pass.
[assembly: FileIOPermissionAttribute(SecurityAction.RequestRefuse,
                                        Unrestricted=false)]

 

友情链接
版权所有 Copyright(c)2004-2021 锐英源软件
公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768
地址:郑州大学北校区院(文化路97号院)内