杂文 – 生活随笔

January 11th, 2010 Arale No comments

刚刚把这个周换下来的衣服统统都丢进了洗衣机里面.  然后利用洗衣服的时间把自己从头到脚好好的洗了个干净. 闻着洗衣粉的味道, 感觉特别有成就感.

抽时间上网的时候看到了一副图片, 很不错, 很像迪士尼的城堡, 当然肯定不是迪士尼那样的. 很漂亮, 很dream, fantasy.

p287604897

最近一直在复习英语词汇, 总想着把自己以前落下的补回来, 可是越急, 就感觉效果越不明显. 新一批的词汇已经从A看到H了. 可是还是着急, 巴不得一下子看到Z. 不过单词就是一个漫长的过程, 看了忘, 忘了看, 反复记忆. 大概要记住这6K个新的单词需要至少半年的时间吧~ 想我突破了这个瓶颈之后就是一个新的自己了.

至于上个月看的WPF, 感觉没什么问题了, 大体各个控件的用法都看了看. 相关的机制也有所了解, 做了几个小例子,感觉还对它的掌握还是比较牢固的. 当然, 还是有一些不足的地方, 应该在后续的开发中就可以弥补了.

同时还在学习怎么做需求分析和系统设计. 已经通读了<<需求分析与系统设计>>, 接下来的<<UML和模式应用>>已经看了一半了吧. 中国的大学教育很害人, 4年的时间教的有用的东西其实并不多, 现在有些后悔浪费了自己的大学时光了.

还看到一幅关于<<笔仙>>的X图,画的很不错, 不知道作者是谁.不过看着很来感.

p376472695

Read more...

程序 – C#写的一个Base64的加密和解密算法

January 9th, 2010 Arale No comments

加密算法

using System;
 
namespace TestBase64
{
  /// <summary>
 
  /// Summary description for Base64Encoder.
 
  /// </summary>
 
  public class Base64Encoder
  {
    byte[] source;
    int length,length2;
    int blockCount;
    int paddingCount;
    public Base64Encoder(byte[] input)
    {
      source=input;
      length=input.Length;
      if((length % 3)==0)
      {
        paddingCount=0;
        blockCount=length/3;
      }
      else
      {
        paddingCount=3-(length % 3);//need to add padding
 
        blockCount=(length+paddingCount) / 3;
      }
      length2=length+paddingCount;//or blockCount *3
 
    }
 
    public char[] GetEncoded()
    {
      byte[] source2;
      source2=new byte[length2];
      //copy data over insert padding
 
      for (int x=0; x<length2;x++)
      {
        if (x<length)
        {
          source2[x]=source[x];
        }
        else
        {
          source2[x]=0;
        }
      }
 
      byte b1, b2, b3;
      byte temp, temp1, temp2, temp3, temp4;
      byte[] buffer=new byte;
      char[] result=new char;
      for (int x=0;x<blockCount;x++)
      {
        b1=source2[x*3];
        b2=source2[x*3+1];
        b3=source2[x*3+2];
 
        temp1=(byte)((b1 & 252)>>2);//first
 
 
        temp=(byte)((b1 & 3)<<4);
        temp2=(byte)((b2 & 240)>>4);
        temp2+=temp; //second
 
 
        temp=(byte)((b2 & 15)<<2);
        temp3=(byte)((b3 & 192)>>6);
        temp3+=temp; //third
 
 
        temp4=(byte)(b3 & 63); //fourth
 
 
        buffer[x*4]=temp1;
        buffer[x*4+1]=temp2;
        buffer[x*4+2]=temp3;
        buffer[x*4+3]=temp4;
 
      }
 
      for (int x=0; x<blockCount*4;x++)
      {
        result[x]=sixbit2char(buffer[x]);
      }
 
      //covert last "A"s to "=", based on paddingCount
 
      switch (paddingCount)
      {
        case 0:break;
        case 1:result='=';break;
        case 2:result='=';
          result='=';
          break;
        default:break;
      }
      return result;
    }
 
    private char sixbit2char(byte b)
    {
      char[] lookupTable=new char[64]
          {  'A','B','C','D','E','F','G','H','I','J','K','L','M',
            'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
            'a','b','c','d','e','f','g','h','i','j','k','l','m',
            'n','o','p','q','r','s','t','u','v','w','x','y','z',
            '0','1','2','3','4','5','6','7','8','9','+','/'};
 
      if((b>=0) &&(b<=63))
      {
        return lookupTable[(int)b];
      }
      else
      {
        //should not happen;
 
        return ' ';
      }
    }
  }
}

解密算法

using System;
 
namespace TestBase64
{
  /// <summary>
 
  /// Summary description for Base64Decoder.
 
  /// </summary>
 
  public class Base64Decoder
  {
    char[] source;
    int length, length2, length3;
    int blockCount;
    int paddingCount;
    public Base64Decoder(char[] input)
    {
      int temp=0;
      source=input;
      length=input.Length;
 
      //find how many padding are there
 
      for (int x=0;x<2;x++)
      {
        if(input[length-x-1]=='=')
          temp++;
      }
      paddingCount=temp;
      //calculate the blockCount;
 
      //assuming all whitespace and carriage returns/newline were removed.
 
      blockCount=length/4;
      length2=blockCount*3;
    }
 
    public byte[] GetDecoded()
    {
      byte[] buffer=new byte[length];//first conversion result
 
      byte[] buffer2=new byte[length2];//decoded array with padding
 
 
      for(int x=0;x<length;x++)
      {
        buffer[x]=char2sixbit(source[x]);
      }
 
      byte b, b1,b2,b3;
      byte temp1, temp2, temp3, temp4;
 
      for(int x=0;x<blockCount;x++)
      {
        temp1=buffer[x*4];
        temp2=buffer[x*4+1];
        temp3=buffer[x*4+2];
        temp4=buffer[x*4+3];        
 
        b=(byte)(temp1<<2);
        b1=(byte)((temp2 & 48)>>4);
        b1+=b;
 
        b=(byte)((temp2 & 15)<<4);
        b2=(byte)((temp3 & 60)>>2);
        b2+=b;
 
        b=(byte)((temp3 & 3)<<6);
        b3=temp4;
        b3+=b;
 
        buffer2[x*3]=b1;
        buffer2[x*3+1]=b2;
        buffer2[x*3+2]=b3;
      }
      //remove paddings
 
      length3=length2-paddingCount;
      byte[] result=new byte[length3];
 
      for(int x=0;x<length3;x++)
      {
        result[x]=buffer2[x];
      }
 
      return result;
    }
 
    private byte char2sixbit(char c)
    {
      char[] lookupTable=new char[64]
          {  
 
    'A','B','C','D','E','F','G','H','I','J','K','L','M','N',
    'O','P','Q','R','S','T','U','V','W','X','Y', 'Z',
    'a','b','c','d','e','f','g','h','i','j','k','l','m','n',
    'o','p','q','r','s','t','u','v','w','x','y','z',
    '0','1','2','3','4','5','6','7','8','9','+','/'};
      if(c=='=')
        return 0;
      else
      {
        for (int x=0;x<64;x++)
        {
          if (lookupTable[x]==c)
            return (byte)x;
        }
        //should not reach here
 
        return 0;
      }
 
    }
 
  }
}

转自code project

Read more...

程序 – C#中关于委托的一个例子

January 9th, 2010 Arale No comments
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
namespace 事件委托2
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
            Form1.myevent += new Form1.mydelegate(fm2_myevent);
 
        }
        void fm2_myevent(string str)
        { 
 
            this.listBox1.Items.Add(str);
 
        }
 
        private void Form2_Load(object sender, EventArgs e)
        {
 
        }
       private  void Form2_Click(object sender, System.EventArgs e)
        {
 
            MessageBox.Show("大家好");
        }
 
        private void SDSJ_Shown(object sender, EventArgs e)
        {
            MessageBox.Show("你好");
        }
        private void Form2_LocationChanged(object sender, EventArgs e)
        {
 
        }
    }
}
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
namespace 事件委托2 
{ 
     public partial class Form1 : Form 
     { 
	Form2 frm = new Form2(); 
	public Form1() 
        { 
           InitializeComponent(); 
           frm.Show(); 
           frm.Hide(); 
        } 
        public delegate void mydelegate(string text);//定义一个委托  
        public static event mydelegate myevent; 
        private void listBox1_MouseDoubleClick(object sender, MouseEventArgs e) 
        { 
           if (myevent != null) 
           { 
               myevent(this.listBox1.SelectedItem.ToString()); 
           } 
        } 
        private void button1_Click(object sender, EventArgs e) 
        { 
            frm.Show(); 
        } 
     } 
}
Read more...

杂文 – 又见大雁向北飞

January 8th, 2010 Arale No comments

早晨等公交车的时候, 看到天空中一群大雁在往北方飞. 我这人一向没有什么方向感, 但是我看大雁飞的方向一定是北方.
如同小学课本上描述的那样, “人”或者是”一”字型, 偶尔有几只掉队的在后面,也是摆着整齐的队形.北方现在正是严寒的冬季, 不知道大雁为什么要去那里? 也许等它们到了的时候, 北方就已经是温暖的春季了? 或者这只是它们普普通通的一次旅游.

不管怎样, 青岛的天空很少能看到一群大雁在飞, 也许是它们飞的太高了我们看不到, 也许是因为城市的污染太严重了, 遮住了本来蓝色的天空.也许是它们本来就在那里, 只是由于繁忙的生活节奏, 生存压力, 我没有抬起头看一看那曾经蔚蓝的天空.

有点想家了.

The goose illution

Read more...

IT – 突破封锁上QQ

January 7th, 2010 Arale 2 comments

“Your people will judge you on what you created instead of what you destroy.”

俗话说, 道高一尺,魔高一丈, 即使是GFW也封锁不住人们对自由信息的向往, 更不用说一小小的公司了.

当然,本人是非常不喜欢使用这个工具的,无奈朋友太多都在上面, 又要联系. 没有办法.不得不用. 当然如果你没有对技术的热忱, 没有一定的IT基础,并对自由的追逐不是那么向往的话建议直接登录web.qq.com或者是silverlight版本的online的QQ. 丫的再封总不能把HTTP也给封掉.

要突破封锁来上QQ的话, 要针对不同的封锁来判断解决的办法.
比如说文件改名, 绕过域登录, 或者是直接对QQ来一个逆向,形成新的文件名. 看到QQ的登录方式有Socket的方式, 也可以用MyEntunnel建立一条ssh管道,通过这条管道访问. 总之是方法多多, 有的时候是要综合上面的方法然后才能解决,这个关键是看人的耐性了. 下面转载的文章的突破方法是封锁最猛的时候才使用的.

哥教的不是违反规定, 是对自由的执着.
其实不管采取何种手段,都得允许正常的网页浏览,这样我们就完全有可能突破封锁。QQ是我们使用最多的交流工具,但是在一些公司里,领导们以上班时间聊天影响工作为由命令网管采取各种手段封杀QQ,使得我们这些QQ迷们不能方便的与好友进行交流。

相信很多朋友一定迫不及待的想知道到底怎么个突破法了吧,其实道理还是比较简单的。你只需要请好友安装SoftEther,然后由它充当虚拟HUB;然后再在本机安装SoftEther,建立一块虚拟网卡,最后只要将虚拟网卡与HUB连接起来,组成一个虚拟的局域网,这样QQ就可以突破封锁了。

一、程序安装
分别在好友与自己的计算机上启动SoftEther安装程序,在安装时由于虚拟HUB控制台是运行于命令行模式的,汉化后的字体比较大,如果不习惯可以选中“使用英文版的虚拟HUB管理控制台”选项;接下来会进行文件复制,复制完毕单击“简体中文”选择使用的语言,这时会弹出安装选项窗口,作为服务器端必须选中所有选项进行安装,而作为客户端,也就是我们自己只需要选中“安装SoftEther虚拟网卡核心组件”选项即可(图1)。

小提示:在安装时可能会弹出兼容性测试窗口,此时只需单击“仍然继续”按钮即可;另外在安装结束时还会弹出配置窗口,这时需要单击“开始”按钮启用虚拟网卡和HUB,如果在这里没有启用的话则需要在开始菜单中打开SoftEther设置中心来开始服务了。

二、配置虚拟HUB
作为服务器,首先从开始菜单中启动“SoftEther虚拟HUB管理器”,在弹出的窗口中默认选择本地计算机,然后单击“连接”按钮,这样即会打开“Telnet Localhost”窗口,并会要求设置密码保护SoftEther虚拟HUB,输入密码后再次确认,会提示密码设置成功,并进入功能菜单(图2),在这里我们需要为客户端创建一个用户,因此在“菜单ID”后输入“1”选择用户管理并回车,此时会打开用户管理的二级子菜单,按下“2”创建新用户,这时会要求输入创建的用户名回车后,继续设置密码,接下来还会进行多个安全选项设置,建议直接按下回车使用默认值即可。

待完成安全选项设置后则会提示用户已创建,这时我们就可以连续两次按下9退出管理程序了。
小提示:我们创建用户的目的就是避免虚拟HUB被网上不明用户占用,创建了用户并添加了密码,这样没有合法帐号就无法使用了。

三、客户端配置
现在我们就可以在自己的电脑上进行配置了。打开“网上邻居”属性窗口,会看到里面有一个“SoftEther Virtual LAN Connection”的连接,打开该连接的属性窗口,选中“Internet协议(TCP/IP)”项单击“属性”按钮,在打开的窗口中选中“使用下面的IP地址”选项,然后将IP地址设为192.168.0.2,子网掩码设为255.255.255.0,网关设为192.168.0.1,DNS设为本地ISP地址,设置完毕单击“确定”保存设置。
接下来打开桌面上的“SOFTETHER连接管理器”,在打开的窗口中单击“帐号”菜单下的“新帐号”命令,在打开的“新连接设置”窗口中为配置新的SoftEther连接帐号输入一个名称,可随便取,只要便于分辩和记忆即可;在“连接到虚拟HUB的通讯协议”中选择“直接TCP/IP连接”项并单击“配置”按钮,在弹出的窗口中输入对方公网真实IP地址,保持默认端口值7777,单击“确定”返回;再选中右侧的“连接虚拟HUB需要使用身份验证”选项,并输入在服务端配置的帐号和密码,做好设置后单击“确定”(图3)。

小提示:为了数据传输的安全,大家可以选中“128位数据包加密方式”选项。

现在我们就可以在SOFTETHER连接管理器窗口左侧双击建立的新帐号,这样在右侧则会显示连接的进程(图4),待连接成功后还会在任务栏上显示一个图标。这个时候我们就可以直接在客户端启动QQ进行登录了。

Read more...

程序 – 带有时区信息的日期转换

January 7th, 2010 Arale No comments

接收到一个日期型的字符串.string value = “Wed Jan 06 17:08:03 +0000 2010″; 其中包含着时区信息+0000, 当然不同的时区,时区也不相同. 将接收到的字符串稍微处理一下.

string value = "Wed Jan 06 17:08:03 +0000 2010"; 
//分割出年、月、日、分、秒、时、星期 
string[] date=value.Split(new char[]{' ',':'},StringSplitOptions.RemoveEmptyEntries); 
//生成本地日期字符串格式,GMT代表根据本地时区日期计算 
string datestr = string.Format("{0}, {1} {2} {3} {4}:{5}:{6} GMT", date[0], date[2], date[1], date[7], date[3], date[4], date[5]); 
//转换成本地日期 //实际日期就出来了,是 星期四, 2010-01-07 01:08:03
 
DateTime dtt = Convert.ToDateTime(datestr);
//在处理相关的时间的时候,下面代码就能实现了.
DateTime now = DateTime.Now;
TimeSpan ts = (TimeSpan)now.Subtract(dtt);
int xday = ts.Days;//获取相差天数
int xhour = ts.Hours;//相差小时
int xmin = ts.Minutes;//相差分钟
int xsec = ts.Seconds;//相差秒数
//相差时间结果
string xTime = string.Format("时间相差{0}天{1}小时{2}分{3}秒",xday,xhour,xmin,xsec);

另外, 提供一个时区和数字的对应, 有需要的可以拿去改改使用

private static string[][] TimeZones = new string[][] 
{
            new string[] {"ACDT", "+1030", "Australian Central Daylight"},
            new string[] {"ACST", "+0930", "Australian Central Standard"},
            new string[] {"ADT", "-0300", "(US) Atlantic Daylight"},
            new string[] {"AEDT", "+1100", "Australian East Daylight"},
            new string[] {"AEST", "+1000", "Australian East Standard"},
            new string[] {"AHDT", "-0900", ""},
            new string[] {"AHST", "-1000", ""},
            new string[] {"AST", "-0400", "(US) Atlantic Standard"},
            new string[] {"AT", "-0200", "Azores"},
            new string[] {"AWDT", "+0900", "Australian West Daylight"},
            new string[] {"AWST", "+0800", "Australian West Standard"},
            new string[] {"BAT", "+0300", "Bhagdad"},
            new string[] {"BDST", "+0200", "British Double Summer"},
            new string[] {"BET", "-1100", "Bering Standard"},
            new string[] {"BST", "-0300", "Brazil Standard"},
            new string[] {"BT", "+0300", "Baghdad"},
            new string[] {"BZT2", "-0300", "Brazil Zone 2"},
            new string[] {"CADT", "+1030", "Central Australian Daylight"},
            new string[] {"CAST", "+0930", "Central Australian Standard"},
            new string[] {"CAT", "-1000", "Central Alaska"},
            new string[] {"CCT", "+0800", "China Coast"},
            new string[] {"CDT", "-0500", "(US) Central Daylight"},
            new string[] {"CED", "+0200", "Central European Daylight"},
            new string[] {"CET", "+0100", "Central European"},
            new string[] {"CST", "-0600", "(US) Central Standard"},
            new string[] {"CENTRAL", "-0600", "(US) Central Standard"},
            new string[] {"EAST", "+1000", "Eastern Australian Standard"},
            new string[] {"EDT", "-0400", "(US) Eastern Daylight"},
            new string[] {"EED", "+0300", "Eastern European Daylight"},
            new string[] {"EET", "+0200", "Eastern Europe"},
            new string[] {"EEST", "+0300", "Eastern Europe Summer"},
            new string[] {"EST", "-0500", "(US) Eastern Standard"},
            new string[] {"EASTERN", "-0500", "(US) Eastern Standard"},
            new string[] {"FST", "+0200", "French Summer"},
            new string[] {"FWT", "+0100", "French Winter"},
            new string[] {"GMT", "-0000", "Greenwich Mean"},
            new string[] {"GST", "+1000", "Guam Standard"},
            new string[] {"HDT", "-0900", "Hawaii Daylight"},
            new string[] {"HST", "-1000", "Hawaii Standard"},
            new string[] {"IDLE", "+1200", "Internation Date Line East"},
            new string[] {"IDLW", "-1200", "Internation Date Line West"},
            new string[] {"IST", "+0530", "Indian Standard"},
            new string[] {"IT", "+0330", "Iran"},
            new string[] {"JST", "+0900", "Japan Standard"},
            new string[] {"JT", "+0700", "Java"},
            new string[] {"MDT", "-0600", "(US) Mountain Daylight"},
            new string[] {"MED", "+0200", "Middle European Daylight"},
            new string[] {"MET", "+0100", "Middle European"},
            new string[] {"MEST", "+0200", "Middle European Summer"},
            new string[] {"MEWT", "+0100", "Middle European Winter"},
            new string[] {"MST", "-0700", "(US) Mountain Standard"},
            new string[] {"MOUNTAIN", "-0700", "(US) Mountain Standard"},
            new string[] {"MT", "+0800", "Moluccas"},
            new string[] {"NDT", "-0230", "Newfoundland Daylight"},
            new string[] {"NFT", "-0330", "Newfoundland"},
            new string[] {"NT", "-1100", "Nome"},
            new string[] {"NST", "+0630", "North Sumatra"},
            new string[] {"NZ", "+1100", "New Zealand "},
            new string[] {"NZST", "+1200", "New Zealand Standard"},
            new string[] {"NZDT", "+1300", "New Zealand Daylight "},
            new string[] {"NZT", "+1200", "New Zealand"},
            new string[] {"PDT", "-0700", "(US) Pacific Daylight"},
            new string[] {"PST", "-0800", "(US) Pacific Standard"},
            new string[] {"PACIFIC", "-0800", "(US) Pacific Standard"},
            new string[] {"ROK", "+0900", "Republic of Korea"},
            new string[] {"SAD", "+1000", "South Australia Daylight"},
            new string[] {"SAST", "+0900", "South Australia Standard"},
            new string[] {"SAT", "+0900", "South Australia Standard"},
            new string[] {"SDT", "+1000", "South Australia Daylight"},
            new string[] {"SST", "+0200", "Swedish Summer"},
            new string[] {"SWT", "+0100", "Swedish Winter"},
            new string[] {"USZ3", "+0400", "USSR Zone 3"},
            new string[] {"USZ4", "+0500", "USSR Zone 4"},
            new string[] {"USZ5", "+0600", "USSR Zone 5"},
            new string[] {"USZ6", "+0700", "USSR Zone 6"},
            new string[] {"UT", "-0000", "Universal Coordinated"},
            new string[] {"UTC", "-0000", "Universal Coordinated"},
            new string[] {"UZ10", "+1100", "USSR Zone 10"},
            new string[] {"WAT", "-0100", "West Africa"},
            new string[] {"WET", "-0000", "West European"},
            new string[] {"WST", "+0800", "West Australian Standard"},
            new string[] {"YDT", "-0800", "Yukon Daylight"},
            new string[] {"YST", "-0900", "Yukon Standard"},
            new string[] {"ZP4", "+0400", "USSR Zone 3"},
            new string[] {"ZP5", "+0500", "USSR Zone 4"},
            new string[] {"ZP6", "+0600", "USSR Zone 5"}
        };
}
Read more...

程序 – Newtonsoft JSON 多级数据的处理方法

January 6th, 2010 Arale No comments

遇到了多级的JSON数据, 需要处理一下, 网上普遍没有现成的代码. 自己研究了一下. 现总结如下.
现在处理的是2级的代码. 是我从twitter上面拉回的JSON格式的User Tweets的一些信息.
信息大概格式为

in_reply_to_screen_name:value,
source:value,
geo:value,
truncated:value,
user:{
     item1:value,
     item2:value,
}

很明显述的JOSN是2层,于是在定义的对象的时候,需要定义2个对象,一个是针对顶层的,另一个是针对第二层user的.

public class Tweet
{
        private string _in_reply_to_screen_name;
        private string _source;
        private string _geo;
        private string _truncated;
        private TweetUser _user;
 
        public string in_reply_to_screen_name
        {
            set { this._in_reply_to_screen_name = value; }
            get { return this._in_reply_to_screen_name; }
        }
        public string source
        {
            set { this._source = value; }
            get { return this._source; }
        }
        public string geo
        {
            get { return this._geo; }
            set { this._geo = value; }
        }
        public string truncated
        {
            set { this._truncated = value; }
            get { return this._truncated; }
        }
        public TweetUser user
        {
            set { this._user = value; }
            get { return this._user; }
        }
}
//根据JSON内的USER的数目来生成相对的对象.
 public class TweetUser
 {
        private string _item1;
        public string item1
        {
            get { }
            set { }
        }
}
//然后构造一个List
public class Tweets:List<Tweet> {}
//这样在前台处理的时候, 就可以直接使用Newtonsoft类来处理了.
Tweets tweets = JsonConvert.DeserializeObject<Tweets>(strJSONValue);
Read more...

WPF – 数据的转换器,又称数值转换器

January 5th, 2010 Arale 1 comment

在WPF中, 可以将转换方法与控件做一个绑定, 在控件触发事件的时候,直接交由WPF的机制来处理.

//这个class是定义在xbap窗体应用程序中的, 如果想写在单独的类里面也可以,但要注意引用命名空间.
//这里重载2个方法, 从数据源到值转换Convert,
//和从值到数据源的转换ConvertBack 
 public class AgeToForcegroundConverter : IValueConverter
 {
   public object Convert(object value, Type targettype, object obj, System.Globalization.CultureInfo info)
   {
        if (targettype != typeof(Brush)) { return null; }
        int age = int.Parse(value.ToString());
        return (age > 25 ? Brushes.Red : Brushes.Green);
   }
   public object ConvertBack(object value, Type targettype, object obj, System.Globalization.CultureInfo info)
   {
         throw new NotImplementedException();
         //return value;
     }
}

前端的xbap页面使用方法.

<Window    
xmlns:local ="clr-namespace:命名空间"    //这一行是定义Windows.Resoures的local标签. 
/>
这里是定义一个转换器
<Window.Resources>
    <local:AgeToForcegroundConverter x:Key="ageConverter"></local:AgeToForcegroundConverter>
</Window.Resources>
<!--这里就是具体的绑定的方法了, 要注意转换器的返回和绑定的属性匹配, 如果是文本型,则绑定tex属性之类.-->
 <TextBox Name="ageTextBox" Foreground="{Bind Path=Age,Converter={StaticResource ageConverter}}" />
<!-- ... ...  -->
<!-- 同样,可以将另一个元素的属性直接与其它控件绑定绑定. 这样当Textbox发生变化, 按钮也会发生变化.-->
<Button Forceground="{Binding Path=Forceground, ElementName=agetTextBox}">

需要注意的一点是, 如果没有在Window.Resources中定义Person的话, 在后台就要给Grid的DataContext属性指定一个我们事先new 出来的Person, 这样转换器才会生效.
另外,注意一下执行的时机.
当数据源将值送给textbox的时候会触发Convert事件, 当textbox将值更新到数据源的时候,会触发Convertback事件.

Read more...

WPF – 当控件值变动时处理方法,用WPF来解决.

January 5th, 2010 Arale No comments

对于WPF数据绑定不太熟悉话,可以参考这篇文章
这里要讲的是当控件的数据发生变动的时候, 如何用WPF机制来解决.
平常在Asp.Net的编程中, 假如说文本框txtAge.Text = “1″, 当按钮点击一下时, 我可以在按钮的事件里面对txtAge.Text重新赋值,从而让控件显示出我在按钮事件的赋值, 这不错, 可以解决问题, 但如果用WPF的方式来说, 可能会显的专业一些.

using System.ComponentModel;//命名空间的引用
public class Person :INotifyPropertyChanged //定义一个人, 让其继承自INotifyPropertyChanged的类.
{
        //PropertyChangedEventHandler属于INotifyPropertyChanged的成员, 这里我们拿来使用.
        public event PropertyChangedEventHandler PropertyChanged;
       //定义处理方法, 当成员发生变化的时候发生的时候,用来通知WPF进行处理.
        protected void Notify(string propName)
        {
            if (this.PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
        string name;
        public string Name 
        {
            get { return this.name; }
            set { this.name = value; }
        }
        int age;
        public int Age
        {
            get { return this.age; }
            set
            {
                if (this.age == value) return;
                else this.age = value;
                Notify("Age");
            }
        }
        public Person() { }
        public Person(string name, int age)
        {
            this.age = age;
            this.name = name;
        }
 
}

前端的XBAP文件.

    <Grid>
        <TextBox Height="23" Margin="74,87,84,0" Name="txtName" VerticalAlignment="Top" />
        <TextBox Height="23" Margin="74,0,84,107" Name="txtAge" VerticalAlignment="Bottom" />
        <Button Height="23" Margin="74,0,130,78" Name="btnClick" VerticalAlignment="Bottom" Click="btnClick_Click">Button</Button>
    </Grid>

XBAP文件的.cs文件中的内容

 public partial class Example : Window
 {
        Person person = new Person("Steven", 25); //这个都知道,就不用说了.
        public Example()
        {
            InitializeComponent();
            this.txtName.Text = person.Name;
            this.txtAge.Text  = person.Age.ToString();
            //由于person继承自INotifyPropertyChanged这个类, 所以我们也可以给他注册一个事件.
           //用于告诉WPF是哪一个成员的值发生了变化. 
           //这里其于值的变化来触发事件,而不根据按钮事件或者是文本框的TextBox Changed来触发事件
            person.PropertyChanged +=new System.ComponentModel.PropertyChangedEventHandler(person_PropertyChanged);
 
        }
        //当按钮按下时, 由于person.Age的值发生了变化, 因此,e.PropertyName的值就是person中的Age属性.
        //根据switch判断, 可知结果.
        void person_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            { 
                case "Name":
                    this.txtName.Text = person.Name;
                    break;
                case "Age":
                    this.txtAge.Text = person.Age.ToString();
                    break;
            }
        }
 
        private void btnClick_Click(object sender, RoutedEventArgs e)
        {
            ++person.Age;
            MessageBox.Show(person.Name + person.Age.ToString());
        }
 }

也许有人会感觉这样很麻烦, 其实两三行代码来说的确很麻烦.
但是当代码量大的时候, 成员的变更交由WPF的PropertyChanged机制来处理,
而不用在各个事件上面写重新赋值代码. 其实是可以起到节省代码的作用的.

Read more...

WPF – Grid布局

January 5th, 2010 Arale No comments

在WPF中使用Grid布局是一件很简单的事情. 如果我们对HTML的表格很熟悉的话, Grid就会得心应手.
与HTML的table不一样的是,grid的布局, 行与列要提前定义, 定义好了之后,再给控件填入位置.
行定义的时候可以使用Height属性,
列定义的时候可以使用Width属性.
使用控件的时候, 要定义控件的Grid.Row和Grid.Column来指定该控件在Grid的哪一个格子里面.
同样的,控件还有Grid.RowSpan和Grid.ColumnSpan, 在了解HTML的Table的语法前提下,这些就不难理解了.

  <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Grid.Column="0" Grid.Row="0">Cell1</TextBlock>
        <TextBlock Grid.Column="1" Grid.Row="0">Cell2</TextBlock>
        <TextBlock Grid.Column="0" Grid.Row="1">Cell3</TextBlock>
        <TextBlock Grid.Column="1" Grid.Row="1">Cell4</TextBlock>
        <TextBlock Grid.Column="0" Grid.Row="2">Cell5</TextBlock>
        <TextBlock Grid.Column="1" Grid.Row="2">Cell6</TextBlock>
    </Grid>
Read more...