当前位置:首页 » C#

C#多国语言的实现 On 程序人生  @2009-08-07

 相关文章:[Winform程序多语言国际化实现的简单方法]
那怎么具体实现不用编译源程序,而实现多国语言的调用,这正是本篇要说的。
1  首先得知道源程序中的资源文件的字段以及对应的值以及该资源文件所处的类名、程序集名和命名空间;
新建一个解决方案(名字跟原项目中相同),而后修改程序集名(跟原项目同名)和命名空间(跟原项目同名);
3 然后添加一个资源文件,名字跟原项目中的资源同名,但是要多个字段,这个字段代表的是什么语言资源文件。样式为:“原项目名.语言.resx”。语言这块可以是zh-CN(中文简体), zh-TW(中文繁体), en-US(英文)等。

4 把第一步中得知的资源文件的字段添加到新建的资源文件中,并把其值修改成相应的语言
5 运行这个项目,在生成目录下会产生一个命名为相应语言的文件夹,
 
拷贝这个文件夹到源程序的运行目录下,这样如果系统是英文的,资源文件就会自动调用en-US这个文件夹

打签» ,   评论» 抢沙发

TabControl初次加载的问题 On 程序人生  @2009-05-04

下图是一TabControl初次加载所显示的,本来其上是用控件的,但是没有显示出来,通过点击其它的page然后再点击它,才会显示其上所用的控件
                                        

 

 

 

 

                         (错误的图)


 

 

 

                         (正确的图)
其实产生这种情况的原因很简单,那是因为,初始化控件和加载控件的先后顺序颠倒了,正确的顺序是先初始化控件,然后把其加载到其父窗体上,不然就会产生第一幅错误的图片。

打签» ,   评论» 抢沙发

解决方案、项目、程序集、命名空间、类 On 程序人生  @2009-04-11

先说说项目(Project),通俗的说,一个项目可以就是你开发的一个软件。在.Net下,一个项目可以表现为多种类型,如控制台应用程序,Windows应用程序,类库(Class Library),Web应用程序,Web Service,Windows控件等等。如果经过编译,从扩展名来看,应用程序都会被编译为.exe文件,而其余的会被编译为.dll文件。既然是.exe文件,就表明它是可以被执行的,表现在程序中,这些应用程序都有一个主程序入口点,即方法Main()。而类库,Windows控件等(.dll),则没有这个入口点,所以也不能直接执行,而仅提供一些功能,给其他项目调用。
再来说说解决方案,在Visual Studio中,新建一个的项目。例如创建控制台应用程序。注意在此时,Visual Studio除了建立了一个控制台项目之外,还创建了一个包含这个控制台项目的解决方案(Solution)。这个解决方案有什么用?如果你只需要开发一个Hello World的项目,解决方案自然毫无用处。但是,一个稍微复杂一点的软件,都需要很多模块来组成,为了体现彼此之间的层次关系,利于程序的复用,往往需要多个项目,每个项目实现不同的功能模块,最后将这些项目组合起来,就形成了一个完整的解决方案。形象地说,解决方案就是一个容器,在这个容器里,分成好多层,好多格,用来存放不同的项目。一个解决方案与项目是大于等于的关系。建立解决方案后,会建立一个扩展名为.sln的文件。
程序集(Assembly),通俗的角度来说,一个项目也就是一个程序集。从设计的角度来说,也可以看成是一个完整的模块(Module),或者称为是包(Package)。因此,一个程序集也可以体现为一个dll文件,或者exe文件。怎样划分程序集也是大有文章的,不过初学者暂时不用考虑它。
命名空间(namespace),这个在C++里面就有这个概念。引入它,主要是为了避免一个项目中,可能会存在的相同对象名的冲突。这个命名空间的定义,没有特殊的要求。不过基本上来说,为了保证其唯一性,最好是用通用资源标志符(Uniform Resource Identifier, 简称"URI")的格式,例如有个www.wincn.org命名空间。可能你留意过在项目中经常要调用的两个命名空间using System和using System.Data,可能你会有是不是前面的命名空间包含后面的命名空间,既然那样只需要写前面的哪个命名空间,为什么还要写两个的疑虑。其实他们俩确实不存在前者包含后者的关系,这样写是为了体现一种层次关系,也使得命名空间的唯一明了。比如说“命名空间”人,这有点大,里面可能存在好多重复的ID,我们可以命名为,中国.人,甚至中国.陕西.人。
有许多初学者,常常把一个项目就理解为一个命名空间。其实这两者没有绝对的联系,在项目里我们也可以定义很多不相同的命名空间。但为了用户便于使用,最好在一个项目中,其命名空间最好是一体的层次结构。在Visual Studio里,我们可以在项目中新建一个文件夹,默认情况下,该文件夹下对象的命名空间,应该是“项目的命名空间.文件夹名”。当然,我们也可以在namespace中修改它。
类(class),其必须在某单个名称空间里面。尽管.net2.0引入了局部类(partial),因为csc编译时程序集不带partial类相关的信息,类还是必须属于单一程序集,且单一名称空间(不同命名空间同一名称的类是不同的类)。也就是说:partial是语法层面的,不是CLR的一部分!类可以通过名称空间整理存储,引入partial关键字的.net2.0解决了类必须在一个cs文件内实现的诟病。

打签»   评论» 抢沙发

Winform程序多语言国际化实现的简单方法 On 程序人生  @2009-04-03

一般来说,Winform窗体里面Label、Button等控件需要不同的语言来表示。现在通过约束资源文件中对应控件名的名称,来到达简化编程的目的。具体方法如下:
先抛块砖,有玉的尽量向我砸过来。
在Resource文件中建立几个资源文件如:Resource1.zh-CN.resx,Resource1.zh-TW.resx,Resource1.en-US.resx。
然后在资源文件resxResource1.zh-CN.resx中添加:
Form1 测试窗体—对应窗体Form1
Form1label1 用户名—对应其上的label1
Form1label2 密码—-类似
Form1button1 保存(&S)—

在资源文件resxResource1.en-US.resx中添加:
Form1 TestForm
Form1label1 User Name
Form1label2 Passwrod
Form1button1 &Save

在资源文件Resource1.zh-TW.resx 略

建立Form1,在上面放几个控件label1,label2,button1。在Form1的构造函数或Form1_Load事件中添加:
(new SelectLanguage()).SetLanguage(this);,就可以实现Winform窗体的国际化,相当的简单方便。
要实现国际化的控件在资源文件中命名规则是: Form窗体 + 控件名称。

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Resources;
using System.Threading;
using System.Globalization;
using System.Windows.Forms;

namespace TestLanguage
{
    public class SelectLanguage
    {

        public SelectLanguage()
        {
        }

        private string formName;

        public ResourceManager GetCurrentCulture()
        {
            //Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("zh-TW");
            ResourceManager rm = new ResourceManager("TestLanguage.Resource.Resource1", Assembly.GetExecutingAssembly());
            return rm;
        }

        public System.Drawing.Bitmap GetImage(string strObjectId)
        {
            ResourceManager rm = GetCurrentCulture();
            object obj = rm.GetObject(strObjectId);
            return (System.Drawing.Bitmap)obj;
        }

        public string getMsg(string strId)
        {
            string currentLanguage = "";
            try
            {
                ResourceManager rm = GetCurrentCulture();
                CultureInfo ci = Thread.CurrentThread.CurrentCulture;
                currentLanguage = rm.GetString(strId, ci);
            }
            catch
            {
                currentLanguage = "Cannot Found:" + strId + " , Please Add it to Resource File.";
            }
            return currentLanguage;

        }

        public void SetLanguage(System.Windows.Forms.Control control)
        {
            //MessageBox.Show(control.GetType().BaseType.Name);
            if (control.GetType().BaseType.Name == "Form")
            {
                formName = control.Name;
                control.Text = getMsg(control.Name);
            }

            for (int i = 0; i < control.Controls.Count; i++)
            {
                //MessageBox.Show(control.Controls[i].GetType().Name + "-" + control.Controls[i].Name);
                switch (control.Controls[i].GetType().Name)
                {
                    case "Label":
                    case "Button":
                    case "CheckBox":
                    case "LinkLabel":
                        control.Controls[i].Text = getMsg(formName + control.Controls[i].Name);
                        break;
                    case "Panel":
                        SetLanguage(control.Controls[i]);
                        break;
                    case "TabControl":
                        TabControl tbc = (TabControl)control.Controls[i];
                        for (int j = 0; j < tbc.TabCount; j++)
                        {
                            tbc.TabPages[j].Text = getMsg(formName + tbc.TabPages[j].Name);
 &
nbsp;                          SetLanguage(tbc.TabPages[j]);
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    }
}

去掉//Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("zh-TW");的注释,
或修改成//Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
你将看到不同的效果。相关的文章:http://www.wincn.org/post/177.html

打签» ,   评论» 抢沙发

C#的事件处理机制 On 程序人生  @2008-12-10

一、了解C#中的预定义事件处理机制

    在写代码前我们先来熟悉.net框架中和事件有关的类和委托,了解C#中预定义事件的处理。

    EventArgs   是包含事件数据的类的基类,用于传递事件的细节。
    EventHandler  是一个委托声明如下

    public delegate void EventHandler( object sender , EventArgs e )
    注意这里的参数,前者是一个对象(其实这里传递的是对象的引用,如果是button1的click事件则sender就是button1),后面是包含事件数据的类的基类。

    下面我们研究一下Button类看看其中的事件声明,以Click事件为例。

         public event EventHandler Click;
    这里定义了一个EventHandler类型的事件Click

    前面的内容都是C#在类库中已经为我们定义好了的。下面我们来看编程时产生的代码。
    private void button1_Click(object sender, System.EventArgs e)
        {
            …
        }

    这是我们和button1_click事件所对应的方法。注意方法的参数符合委托中的签名(即参数列表)。那我们怎么把这个方法和事件联系起来呢,请看下面的代码。
    this.button1.Click += new System.EventHandler(this.button1_Click);
    把this.button1_Click方法绑定到this.button1.Click事件。

    下面我们研究一下C#事件处理的工作流程,首先系统会在为我们创建一个在后台监听事件的对象(如果是button1的事件那么监听事件的就是button1),这个对象用来产生事件,如果有某个用户事件发生则产生对应的应用程序事件,然后执行订阅了事件的所有方法。

二、简单的自定义事件(1)

    首先我们需要定义一个类来监听客户端事件,这里我们监听键盘的输入。

    定义一个委托。

        public delegate void UserRequest(object sender,EventArgs e);

    前面的object用来传递事件的发生者,后面的EventArgs用来传递事件的细节,现在暂时没什么用处,一会后面的例子中将使用。

    下面定义一个此委托类型类型的事件

        public event UserRequest OnUserRequest;

    下面我们来做一个死循环

     public void Run()     {      bool finished=false;      do      {       if (Console.ReadLine()=="h")       {        OnUserRequest(this,new EventArgs());       }        }while(!finished);    }

    此代码不断的要求用户输入字符,如果输入的结果是h,则触发OnUserRequest事件,事件的触发者是本身(this),事件细节无(没有传递任何参数的EventArgs实例)。我们给这个类取名为UserInputMonitor。

   下面我们要做的是定义客户端的类   首先得实例化UserInputMonitor类

       UserInputMonitor monitor=new UserInputMonitor();

    然后我们定义一个方法。

       private void ShowMessage(object sender,EventArgs e)
      {
          Console.WriteLine("HaHa!!");
      }

     最后要做的是把这个方法和事件联系起来(订阅事件),我们把它写到客户端类的构造函数里。

     Client(UserInputMonitor m)
     {
        m.OnUserRequest+=new UserInputMonitor.UserRequest(this.ShowMessage);
        //m.OnUserRequest+=new m.UserRequest(this.ShowMessage);
       //注意这种写法是错误的,因为委托是静态的
     }

     下面创建客户端的实例。

         new Client(monitor);

     对了,别忘了让monitor开始监听事件。

        monitor.run();

     大功告成,代码如下:

using System;class UserInputMonitor{ public delegate void UserRequest(object sender,EventArgs e); //定义委托 public event UserRequest OnUserRequest; //此委托类型类型的事件 public void Run() {  bool finished=false;  do  {   if (Console.ReadLine()=="h")   {    OnUserRequest(this,new EventArgs());   }    }while(!finished); }} public class Client{ public static void Main() {  UserInputMonitor monitor=new UserInputMonitor();  new Client(monitor);  monitor.Run(); } private void ShowMessage(object sender,EventArgs e) {  Console.WriteLine("HaHa!!"); } Client(UserInputMonitor m) {  m.OnUserRequest+=new UserInputMonitor.UserRequest(this.ShowMessage);  //m.OnUserRequest+=new m.UserRequest(this.ShowMessage);  //注意这种写法是错误的,因为委托是静态的 }}

三、进一步研究C#中的预定义事件处理机制

    可能大家发现在C#中有些事件和前面的似乎不太一样。例如

      private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
      {

      }

      this.textBox1.KeyPress+=newSystem.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress);

    这里使用了KeyPressEventArgs而不是EventArgs作为参数。这里使用了KeyEventHandler委托,而不是EventHandler委托。

    KeyPressEventArgs是EventArgs的派生类,而KeyEventHandler的声明如下

      public delegate void KeyEventHandler( object sender , KeyEve
ntArgs e );

   是参数为KeyEventArgs的委托。那为什么KeyPress事件要这么做呢,我们可以从两个类的构造函数来找答案。

       public EventArgs();
       public KeyPressEventArgs(char keyChar);

    这里的keyData是什么,是用来传递我们按下了哪个键的,哈。
    我在KeyEventArgs中又发现了属性

       public char KeyChar { get; }

    进一步证明了我的理论。下面我们来做一个类似的例子来帮助理解。

四、简单的自定义事件(2)

    拿我们上面做的例子来改。

    我们也定义一个EventArgs(类似KeyEventArgs)取名MyEventArgs,定义一个构造函数public MyEventArgs(char keyChar),同样我们也设置相应的属性。代码如下

using System;class MyMyEventArgs:EventArgs{ private char keyChar; public MyMyEventArgs(char keyChar) {  this.keychar=keychar; } public char KeyChar {  get {  return keyChar; } }}

因为现在要监听多个键了,我们得改写监听器的类中的do…while部分。改写委托,改写客户端传递的参数。好了最终代码如下,

using System;
class MyEventArgs:EventArgs
{
    private char keyChar;
    public MyEventArgs(char keyChar)
    {
         this.keyChar=keyChar;
     }
    public char KeyChar
    {
         get {  return keyChar; }
     }
}
 
class UserInputMonitor
{
public delegate void UserRequest(object sender,MyEventArgs e);
//定义委托
public event UserRequest OnUserRequest;
//此委托类型类型的事件
public void Run()
{
  bool finished=false;
  do
  {
   string inputString= Console.ReadLine();
   if (inputString!="")
    OnUserRequest(this,new MyEventArgs(inputString[0]));
  }while(!finished);
}
}

public class Client
{
public static void Main()
{
  UserInputMonitor monitor=new UserInputMonitor();
  new Client(monitor);
  monitor.Run();
}
private void ShowMessage(object sender,MyEventArgs e)
{
  Console.WriteLine("捕捉到:{0}",e.KeyChar);
}
Client(UserInputMonitor m)
{
  m.OnUserRequest+=new UserInputMonitor.UserRequest(this.ShowMessage);
  //m.OnUserRequest+=new m.UserRequest(this.ShowMessage);
  //注意这种写法是错误的,因为委托是静态的
}
}

打签»   评论» 抢沙发

C#中关于get和set的详细例子介绍 On 程序人生  @2008-11-03

get set是用来扩展域的,也就是C里的变量,只是用起来更加灵活而己。看以下代码: 

using System; 

public class cls 

    private int book;      //定义一个域(也可以叫变量,只是面向对像里都这么叫,使用起来也更加方便) 

    public int Book 

   { 

        get 

           { 

                 Console.WriteLine("dsf"); 

                 return book; 

            } 

        set 

            { 

                  Console.WriteLine("aaa"); 

                  book=value; 

             } 

     } 

    public static void Main() 

    { 

         cls obj = new cls(); 

         obj.Book = 120;         //注意这一句 

         Console.WriteLine(obj.Book); 

     } 

运行结果为: 

aaa 

dsf 

120 

也就是先把120赋值给value(相当一个存储空间),然后再调用  book=value;  然后再用get{}返回给Book,实际上也就是一次改变变量值的过程。 

那你也许会问为什么要这么复杂呢?因为这是用了嵌套,所以可以更加方便的写入其它语句,在以后你就应该学到了。 

如果没有: 

obj.Book = 120; 

请想一想会是什么结果呢? 

只是一个取值过程:get{}而没有执行set{} 

结果为: 

dsf 

0

打签»   评论» 1枚