人生是一场不能存盘的RPG,我只能尽量多搞几个Screenshot

February 28, 2007

String Resource使用

Filed under: .NET

1.方法1
把resource文件(Strings.resx和Strings.zh-CHS.resx)作为Embedded Resource build到Assembly中.
假定生成的assembly的default namespace为MyApp,resource位于Res 目录下,
则会在assembly中生成名为MyApp.Res.Strings.resources的resource,
同时生成zh-CHS目录,及:GMailClient.resources.dll,其中包含名为GMailClient.Res.Strings.zh-CHS.resources的资源.

//First parameter is: Assemlby default namespace + folder + base resource name
//Second parameter is : Assembly contails the
resourceManager = new ResourceManager(”MyApp.Res.Strings”, System.Reflection.Assembly.GetExecutingAssembly());
StringResources.GetString(resId);

测试:
使用 System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(”zh-CN”);
设定UICulture,ResourceManager会使用这个Culture来读取对应的resource.

注意:Culture ‘zh-CHS’ is a neutral culture(与某种语言关联但不与国家/地区关联的区域性). It cannot be used in formatting and parsing and therefore cannot be set as the thread’s current culture.BUT, Culture ‘zh-CHS’ can be set as Current UI Culture.
在这里,我有意生成名为GMailClient.Res.Strings.zh-CHS.resources的resource(Chinese, neutral),但设定UICulture为zh-CN(PRC:Special),读取结果正确.可推测其逻辑为:对于一个Special Culture,找不到相应的
资源,就尝试其对应的neutral culture对应的资源.

对于NeutralCulture和:specified culture可以使用下面的函数进行转化
public static CultureInfo GetNeutralCulture(string cultureName)
{
System.Globalization.CultureInfo c = new System.Globalization.CultureInfo(cultureName);
if (! c.IsNeutralCulture)
{
c = new System.Globalization.CultureInfo(c.LCID & 0x3FF); //低10位
}
return c;
}
举例
zh-CHS 0x0004 Chinese (Simplified) , Neutral
zh-CN 0x0804 Chinese - China

zh-CHT 0x7C04 Chinese (Traditional) , Neutral
zh-TW 0x0404 Chinese - Taiwan
zh-HK 0x0C04 Chinese - Hong Kong SAR
zh-MO 0x1404 Chinese - Macao SAR
zh-SG 0x1004 Chinese - Singapore

下面的代码可以显示zh的相关的culture
foreach ( CultureInfo ci in CultureInfo.GetCultures( CultureTypes.AllCultures ) )
{
if ( ci.TwoLetterISOLanguageName == “zh” )
{
Console.Write( “{0,-6} {1,-40}”, ci.Name, ci.EnglishName );
if ( ci.IsNeutralCulture ) {
Console.WriteLine( “: neutral” );
}
else {
Console.WriteLine( “: specific” );
}
}
}
/*
This code produces the following output.

zh-CHS Chinese (Simplified) : neutral
zh-TW Chinese (Taiwan) : specific
zh-CN Chinese (People’s Republic of China) : specific
zh-HK Chinese (Hong Kong S.A.R.) : specific
zh-SG Chinese (Singapore) : specific
zh-MO Chinese (Macao S.A.R.) : specific
zh-CHT Chinese (Traditional) : neutral

*/

方法2:自己搞

public class PublicResourcesManager
{
private ResXResourceReader _resXReader;
private IDictionaryEnumerator _resXEnum;

public PublicResourcesManager(string resourceRootFolder, string resourceFileName)
{
CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentUICulture;
string resourceFolder = resourceRootFolder.TrimEnd(’\\’);
string fileName = String.Format(”{0}\\{1}\\{2}”, resourceFolder, ci.Name, resourceFileName);

try
{
// first try [country][region] folder…
_resXReader = new ResXResourceReader(fileName);
_resXEnum = _resXReader.GetEnumerator();
if (_resXEnum!=null)
return;
}
catch(Exception ex) {}

_resXReader.Close();

try
{
// try [country] folder (if culture isn’t a neutral culture…
if (!ci.IsNeutralCulture)
{
ci = new CultureInfo(ci.LCID & 0x03ff);

fileName = String.Format(”{0}\\{1}\\{2}”, resourceFolder, ci.Name, resourceFileName);
_resXReader = new ResXResourceReader(fileName);

_resXEnum = _resXReader.GetEnumerator();
if (_resXEnum!=null)
return;
}
}
catch(Exception ex) {}

_resXReader.Close();

try
{
// just try root folder…
fileName = String.Format(”{0}\\{1}”, resourceFolder, resourceFileName);
_resXReader = new ResXResourceReader(fileName);
_resXEnum = _resXReader.GetEnumerator();
}
catch(Exception ex)
{
string err = ex.Message;
}
}

public string GetString(string name)
{
string str = “”;

if (_resXEnum != null)
{
_resXEnum.Reset();
while (_resXEnum.MoveNext())
{
if (string.Compare(name, _resXEnum.Key.ToString(), true, CultureInfo.InvariantCulture)==0)
str=(string)_resXEnum.Value;
}
}
return str;
}
}

此处的逻辑是先找Folder\CultureName\Resource来找
如果失败,就把Culture转成neutral culture,再按Folder\CultureName\Resource找一次.
再失败,就尝试Folder\Resource

最常用的还是.net自己提供的resource管理机制,
在Form的property grid中可以设定form的Language,会为Form自动生成该Language的resource:
如MainForm.zh-CHS.resx,这些resource会被设置为Embedded Resource,其内容为:
<data name=”$this.Icon” type=”System.Drawing.Icon, System.Drawing”>
<value>…Binary Content…<value>
</date>
<data name=”$this.Text” type=”System.Drawing.Icon, System.Drawing”>
<value>Hello!<value>
</date>

在InitializeComponent()会生成代码
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));

resources.ApplyResources(this, “$this”);
resources.ApplyResources(this.pictureBox1, “pictureBox1″);

把resourc中的内容读出,并设置到from上.

3.使用时:
this.pictureBox1.Image = global::MyApplication.Properties.Resources.Winter;
不要轻易手动修改这些自动生成的代码,容易乱套.

February 26, 2007

收假了

Filed under: 随便说说

收假了,对我而言,这才是新年的开始.整个假期,我基本没有碰平时常看的技术站点.
今天打开ie和FeedDemon,不禁感有排山倒海,扑面而来的感觉.
Google Doc上线了.
MSDN Magazine也有了新的issue.
Scott 也没闲着.

够我看一阵子的.

February 13, 2007

.NET 2.0 中字符串比较

Filed under: Uncategorized

常用的string一般有两种:
1. 和culture相关,用于给用户显示,或由用户选择.
2. hardcode到代码中,由developer来使用.

在.net1.0中常用的字符串比较函数为:
String.Compare (String, String)
String.Compare (String, String, Boolean)
String.Compare (String, String, Boolean, CultureInfo)

在.net2.0中,提供了新的字符串比较函数
String.Compare (String, String, StringComparison)

对于Culture-specific strings,请使用:
if (String.Compare(”MyUserDefinedStrng”, “MYUSERDEFINEDSTRING”, StringComparison.CurrentCultureIgnoreCase) == 0)
{}
当然如果不使用第3个参数,缺省也使用current culture,但是使用后可以明确意图,方便代码维护.

对于 Invariant-specific strings,请使用:
if (String.Compare(”MyHardCodedString”, “MYHARDCODEDSTRING”, StringComparison.OrdinalIgnoreCase) == 0)
{}

NB: 不要使用StringComparison.InvariantCulture 和StringComparison.InvariantCultureIgnoreCase 选项
原因请参照:
New Recommendations for Using Strings in Microsoft .NET 2.0中
What About the Earlier Recommendation for Invariant Culture?一节:

InvariantCulture is culture-independent and culture-insensitive, You can specify the invariant culture by name using an empty string (”") or by its culture identifier 0x007F.
It is associated with the English language but not with any country/region.

参考:
New recommendations for string comparisons in .Net 2.0
(http://msdn2.microsoft.com/en-us/library/ms973919.aspx)
Performing Culture-Insensitive String Comparisons
(ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_fxwalkthrough/html/abae50ef-32f7-4a50-a540-fd256fd1aed0.htm)

Writing Compilers and Interpreters 2e的source code

Filed under: 技术书籍

http://www.wiley.com/legacy/compbooks/catalog/11353-0.htm

ftp://ftp.wiley.com/public/computer_books/Software_Development/Mak-Writing_Compilers/

模拟一个文件被cut后Icon的半透明效果

Filed under: ASP.NET

在一个tree 空间中进行的实验:
function AfterNodeSelChange(treeId, nodeId)
{
var selectNode = document.getElementById(nodeId);
var subElements = selectNode.children;
for(x=0; x<subElements.length; x++)
{
var subElement = subElements.item(x);
if(subElement.tagName == ‘IMG’)
{
if(subElement.src != ‘’)
{
subElement.style.cssText = “filter:progid:DXImageTransform.Microsoft.Alpha(opacity=50);”;
}
}
}

//selectNode.filters.item(”DXImageTransform.Microsoft.Alpha”).opacity=50;
}

February 9, 2007

Writing Quality Code by FxCop team

Filed under: .NET

Fxcop team 发布了一本九十几页的小书<<The Quality Code Handbook>>
http://blogs.msdn.com/fxcop/archive/2007/02/07/free-writing-quality-code-e-book-with-information-on-both-native-and-managed-code-analysis.aspx
该书使用的文件格式并不常见,需要阅读工具:http://www.dnaml.com/

February 8, 2007

About Infargistics UltraWebTree NodeChanged Event

Filed under: ASP.NET

UltraWebTree在缺省情况下,
<AutoPostBackFlags NodeChanged=”false” /> 就是在client edit一个node,并不会引发
server 端的NodeChanged event,但奇怪的是如果给NodeClicked event 指定了一个
event handler, NodeChanged event就会被触发,神奇.

February 5, 2007

在Client JavaScript中支持多语言

Filed under: ASP.NET

一个小小的Trick:
在server端读出语言相关的字符串资源并注入到client端:
System.Text.StringBuilder sb = new System.Text.StringBuilder();

sb.Append(”<script type=’text/javascript’>”);
sb.Append(”var I18N = new Array();\n”);
sb.AppendFormat(”I18N[’{0}’] = ‘{1}’;\n”, “my_String_1″, GetResourceString(”my_String_1″));
sb.AppendFormat(”I18N[’{0}’] = ‘{1}’;\n”, “my_String_2″, GetResourceString(”my_String_2″));
sb.Append(”</script>”);

ClientScript.RegisterClientScriptBlock(GetType(), “I18N”, sb.ToString());

在客户端进行读取:
function getI18N(resourceId)
{

return I18N[resourceId];

}

var myString1 = getI18N(”myString_1″))

February 3, 2007

如何在关闭ModalDialog时避免打开新的IE窗口

Filed under: ASP.NET

很多时候,asp.net程序需要弹出一个Modal Dialg来收集用户的输入,这个Modal Dialg会有”OK”,”Cancel”两个button,使用javascript关闭dialog,但是有一些猫腻会导致在Modal Dialg中点击了”OK”或”Cancel”后,不但dialog不关闭反而打开一个新的IE.

原因就在于如果点击button导致了页面的提交,就会出现上述情况,如果这个Modal Dialg所对应的aspx页面是用vs自动生成,asp:button缺省就会提交页面,
此时如果在页面的<head></head>中添加<base target=_self></base>,就可以防止打开新的IE,但故事并没有结束,如果不幸在页面的form中,指定了
<form id=”form1″ runat=”server” target=”_self”>
用上述方法也阻止不了新的IE弹出.此时,需要使用更强大的手段:及在page load时指定form1的target:
javaScript:
function handleOnLoad()
{
window.name = ‘dialognew’ + Number(new Date()).toString();
document.dialognew.target = window.name;
}
form:
<form id=”dialognew” method=”post” target=”_self” runat=”server”>






















Get free blog up and running in minutes with Blogsome
Theme designed by Hadley Wickham