最近玩WP7发现了一个很好玩的框架:Caliburn.Micro。玩了几天,遇到了一些问题,总结备忘一下。关于Caliburn.Micro(简称CM),它官方网站有详细的介绍:http://caliburnmicro.codeplex.com/主要是一个轻量级的MVVM,MVP和MVC框架,可用于WPF,silverlight和WP7
在这里我以CM包里面一个简单的例子(Caliburn.Micro.HelloWP7)来介绍遇到过的问题。


1. 在这里 http://caliburnmicro.codeplex.com/releases/view/67451 下载CM包,解压


2. 打开samples目录下的Caliburn.Micro.HelloWP7项目   


3. 首先需要注意的引用程序集,对于wp,

需要引用下面程序集:   

Caliburn.Micro   

Caliburn.Micro.Extension   

System.Windows.Interactivity   

这三个dll,在\bin\WP7\Release 都可以找到


4. 我们发现HelloWP7有一个类:HelloWP7Bootstrapper 

 这个类是用于引导或初始化windows phone项目,初始化Caliburn配置信息,例如协约,ViewModel等


5. 有了HelloWP7Bootstrapper后,还必须在App.xaml中应用程序资源中添加HelloWP7Bootstrapper

<Application.Resources>
<local:HelloWP7Bootstrapper x:Key="bootstrapper" />
</Application.Resources>


6. 上面我们知道HelloWP7Bootstapper用于初始化WP,   因此,我们要清空App.xaml.cs里面的其它初始化代码,只剩下如下代码:

namespace Caliburn.Micro.HelloWP7 {
using System.Windows;

public partial class App : Application {
public App() {
InitializeComponent();
}
}
}

对于什么要清掉这段代码,官方网站做了这样的解释:Important Note About App.xaml.cs
If you create your WP7 application using a standard Visual Studio template, the generated App.xaml.cs file will have a lot of code in it. The purpose of this code is to set up the root frame for the application and make sure everything gets initialized properly. Of course, that's what the bootstrapper's job is too (and in fact it does a few things better than the out-of-the-box code in addition to configuring CM). So, you don't need both. When using CM's PhoneBootstrapper, be sure to clear out all the code from the App.xaml.cs file except for the call to InitializeComponent in the constructor.


7. 以上几个步骤基本就已经搭建好一个CM环境了,那么CM是如何将界面xaml代码和业务逻辑分开呢?   在HelloWP7项目我们可以看到MainPage还有另外一个类文件 MainPageViewModel.cs,而这个文件正是用于处理MainPage业务逻辑的   那他是怎么跟MainPage关联起来的呢?   我们再看回HelloWP7Bootstrapper类的config函数,我们可以看到以下代码:

container = new PhoneContainer(RootFrame);
container.RegisterPhoneServices();
container.PerRequest
<MainPageViewModel>();

这里第一二行代码是必须的,一定不能删!!container.PerRequest<MainPageViewModel>() 则是讲MianPage注册为一个服务处理每个请求。是否这样MainPage和MainPageViewModel就能联系起来呢?还差一点点


8. 命名规则   要在ViewModel处理业务逻辑不当是要在Bootstrapper中注册ViewModel,还需要特定的命名规则。   对于MainPage的命名规则是 MainPage+ViewModel 也就是MainPageViewModel   但是,对于其它新增的页面就有所区别,新增的必须是以View结尾,比如 LoginView.xaml,RegistView.xaml   而VM的类名必须是LoginViewModel.cs, RegistViewModel.cs。   这里需要注意是MainPage跟其它页面的区别,否则navigate的时候会有NullReference异常。


9. 使用ViewModel处理页面事件   CM使用元素的Name属性来关联前台和ViewModel的关系。   例如:xaml有个x:Name="btnLogin"的按钮,那么ViewModel添加一个btnLogin的共有函数,你就可以在btnLogin函数中处理这个按钮的逻辑      对于SelectedChange事件则必须使用CM中的message机制,比如我们需要将View中ListBox的SelectedChanged交给ViewModel处理   我们必须为ListBox添加以下属性:   cal:Message.Attach="[Event SelectionChanged] = [Action SelectionChanged($source)]"   这里很好理解,Event制定要绑定的事件,Action指定ViewModel处理的事件。即:

ItemTemplate="{StaticResource NewsListItemTemplate}"
ItemsSource
="{Binding Items}"
cal:Message.Attach
="[Event SelectionChanged] = [Action SelectionChanged($source)]"
ItemContainerStyle
="{StaticResource ListBoxItemStyle}"
HorizontalContentAlignment
="Stretch"
ScrollViewer.VerticalScrollBarVisibility
="Disabled"/>

而ViewModel只要添加一个公用的函数SelectionChanged方法就可以了:

public void SelectionChanged(object sender)
{
var listBox
= (ListBox) sender;
if (listBox.SelectedIndex == -1)
return;
//do whatever you want...
}


10. 通过ViewModel绑定ListBox数据    CM提供了一个用于自动绑定UI线程元素的类BindableCollection    具体用法是在ViewModel声明一个公有成员变量   

public BindableCollection<News> Items { get; private set; }   

这个变量用于保存你的所有数据,在构造函数初始化它,并在特定地方为它添加数据

那么页面ListBox如果使用Items中的值呢,方法很简单,只需要指定ListBox的ItemSource为Items就可以了

<ListBox Height="auto" Name="listBox1" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>


11. CM的navigation    在HelloWP的MainPageViewModel中我们可以看到它的构造函数是这样的:        

public MainPageViewModel(INavigationService navigationService)
{
this.navigationService = navigationService;
}

 这里INavigationService就是CM提供用于navigation的接口。 CM 1.1 支持通过ViewModel来跳转页面,所以用起来很方便,具体代码可以参考HelloWP中的GotoPageTwo()方法。


12. 如何在ViewModel中获取界面控件?   

CM提供了一个类Screen,用于获取当前的界面。因此,我们只要在ViewModel中继承Screen,通过GetView()方法就可以获取view实例。   

MainPage view = (MainPage)GetView(null);    通过view就可以获取页面控件啦。

好了,先总结到这了,enjoy it  :-)

posted @ 2011-06-23 16:07 Chris Cheung 阅读(206) 评论(3) 编辑

之前一篇文章写了关于使用mongodb来进行replication,然后发现对于fileserver来说,只是单纯的replicate还不够,因为我们不可能只是使用一台机器来作为fileserver。

于是尝试试用mongodb的auto-shard来进行分布式存储,搞了一整天终于能够搭好环境,下面贴一下配置信息,备忘一下。

主要参考了两篇文章,这里面如何配置都讲得很详细,不过我还是按照自己的方法写一下我的步骤

http://www.cnblogs.com/daizhj/archive/2010/09/07/1820528.html  

http://www.mongodb.org/display/DOCS/A+Sample+Configuration+Session

1. 复制三份mongodb文件,同时在各个文件夹下建立data文件夹用于保存数据库

D:\mongodb1\

D:\mongodb2\

D:\mongodb3\

2. 开始配置,db1,db2作为shard节点,db3作为config server以及mongos

db1和db2的配置一样:

cd d:\mongodb1\bin

mongod --shardsvr --dbpath d:\mongodb1\data --logpath d:\mongodb1\log\logs.log --port 10000 

cd d:\mongodb2\bin

mongod --shardsvr --dbpath d:\mongodb2\data --logpath d:\mongodb2\log\logs.log --port 10001 

db3 config server 配置:

cd d:\mongodb3\bin

mongod --configsvr --dbpath d:\mongodb3\data --logpath d:\mongodb3\log\logs.log --port 20000

db3 mongos 配置:

mongos --configdb 127.0.0.1:20000

这里mongos是用来路由到各个shard节点,因此客户端只需要连接到mongos,无需要直接连接到shard节点,这里没有指定端口号,所以为默认端口号27017

在看上面两篇文章的配置中,我还以为mongos的端口号就是20000,甚至还以为链接字符串应该是把所有的节点写上,囧,所以为了避免困惑还是写上端口好。

mongos --port 30000 --configdb 127.0.0.1:20000

--configdb 用于指定配置服务器地址,可以多个,用逗号隔开

3.  链接到mongos,配置shard

cd d:\mongodb3\bin

mongo

use admin

db.runCommand({addshard:"127.0.0.1:10000",name:"shard1",maxSize:40000})

db.runCommand({addshard:"127.0.0.1:10001",name:"shard2"})

Now you need to tell the database that you want to spread out your data at a database and collection level. You have to give the collection a key (or keys) to partition by.
This is similar to creating an index on a collection.(http://www.mongodb.org/display/DOCS/A+Sample+Configuration+Session)

db.runCommand({enablesharding:"ecDoc"})

db.runCommand({shardcollection:"ecDoc.files.chunks",key:{files_id:1}})

这里我使用的是GridFS来保存文件,所以根据http://www.mongodb.org/display/DOCS/Choosing+a+Shard+Key

shard key的作用还是比较模糊。

posted @ 2011-02-12 02:08 Chris Cheung 阅读(235) 评论(0) 编辑

      上篇文章说了一下怎么试用MongoDB来做replication,但是我是通过BSON Object来保存文件,这有个局限,就是如果文件超过4m就会抛出超过最大文件的异常。

根据官网介绍,BSON objects in MongoDB are limited to 4MB in size.   http://www.mongodb.org/display/DOCS/GridFS

 

因此重新写了那个操作类,使用GridFS来保存文件,代码很简单,但开始接触弄了比较长时间,有一个问题一直解决不了,我希望自己生成一个Guid的 _id 而不是mongodb生成的_id,但是一直解决不了,希望哪个高手看到指点一下,谢谢!

 

这个是使用Mongodb官网提供的客户端写的:

 

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using MongoDB.Bson;
using MongoDB.Driver.GridFS;

namespace FileUtility
{
    public class DocUtility
    {
        private string connStr = "";
        public string ConnStr
        {
            get 
            {
                if (string.IsNullOrEmpty(connStr))
                {
                    throw new ArgumentNullException("Connection string did not specify!");
                }
                return connStr;
            }
        }
        public DocUtility()
        {
            connStr = System.Configuration.ConfigurationManager.AppSettings["FileDb"];
        }

        public DocUtility(string connectionString)
        {
            this.connStr = connectionString;
        }

        /// <summary>
        /// add a document to mongodb
        /// </summary>
        /// <param name="content">document bytes array</param>
        /// <returns>the unique identity filename in mongodb</returns>
        public string AddDoc(byte[] content)
        {
            MongoServer server = MongoServer.Create(this.ConnStr);
            try
            {
                string filename = Guid.NewGuid().ToString();
                server.Connect();
                MongoDatabase db = server.GetDatabase("ecDocs");
                MongoGridFS fs = new MongoGridFS(db, new MongoGridFSSettings() { Root="ecDocs" });
                MongoGridFSFileInfo info = new MongoGridFSFileInfo(fs, filename);
                using (MongoGridFSStream gfs = info.Create())
                {
                    gfs.Write(content, 0, content.Length);
                }
                return filename;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (server != null)
                    server.Disconnect();
            }
        }

        /// <summary>
        /// delete doc from mongodb
        /// </summary>
        /// <param name="filename">the unique identity filename</param>
        public string DeleteDoc(string filename)
        {
            MongoServer server = MongoServer.Create(this.ConnStr);
            try
            {
                server.Connect();
                MongoDatabase db = server.GetDatabase("ecDocs");
                MongoGridFS fs = new MongoGridFS(db, new MongoGridFSSettings() { Root = "ecDocs" });
                fs.Delete(filename);
                return filename;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (server != null)
                    server.Disconnect();
            }
        }

        /// <summary>
        /// get document bytes array from mongodb
        /// </summary>
        /// <param name="filename">unique filename</param>
        /// <returns>bytes array</returns>
        public byte[] GetDoc(string filename)
        {
            MongoServer server = MongoServer.Create(this.ConnStr);
            try
            {
                server.Connect();
                MongoDatabase db = server.GetDatabase("ecDocs");
                MongoGridFS fs = new MongoGridFS(db,new MongoGridFSSettings() { Root="ecDocs" });
                byte[] bytes = null;
                using (MongoGridFSStream gfs = fs.Open(filename, FileMode.Open))
                {
                    bytes = new byte[gfs.Length];
                    gfs.Read(bytes, 0, bytes.Length);
                }
                return bytes;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (server != null)
                    server.Disconnect();
            }
        }
    }
}

 

下面这个类是使用Samus的客户端:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB;
using MongoDB.GridFS;

namespace FileUtilitySamus
{
    public class DocUtility
    {
        private string connStr = "";
        public string ConnStr
        {
            get
            {
                if (string.IsNullOrEmpty(connStr))
                {
                    throw new ArgumentNullException("Connection string did not specify!");
                }
                return connStr;
            }
        }
        public DocUtility()
        {
            connStr = System.Configuration.ConfigurationManager.AppSettings["FileDb"];
        }

        public DocUtility(string connectionString)
        {
            this.connStr = connectionString;
        }

        /// <summary>
        /// add a document to mongodb
        /// </summary>
        /// <param name="content">document bytes array</param>
        /// <returns>the unique identity filename in mongodb</returns>
        public string AddDoc(byte[] content)
        {
            using (Mongo mongo = new Mongo(this.ConnStr))
            {
                try
                {
                    string filename = Guid.NewGuid().ToString();

                    mongo.Connect();
                    IMongoDatabase db = mongo.GetDatabase("ecDoc");

                    GridFile fs = new GridFile(db, "ecDoc");
                    GridFileInfo info = new GridFileInfo(db, "ecDoc", filename);
                    using (GridFileStream gfs = info.Create())
                    {
                        gfs.Write(content, 0, content.Length);
                    }

                    return filename;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        /// <summary>
        /// delete doc from mongodb
        /// </summary>
        /// <param name="filename">the unique identity filename</param>
        public void DeleteDoc(string filename)
        {
            using (Mongo mongo = new Mongo(this.ConnStr))
            {
                try
                {
                    mongo.Connect();
                    IMongoDatabase db = mongo.GetDatabase("ecDoc");

                    GridFile fs = new GridFile(db, "ecDoc");

                    fs.Delete(new Document("filename", filename));
                    
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        /// <summary>
        /// get document bytes array from mongodb
        /// </summary>
        /// <param name="filename">unique filename</param>
        /// <returns>bytes array</returns>
        public byte[] GetDoc(string filename)
        {
            using (Mongo mongo = new Mongo(this.ConnStr))
            {
                try
                {
                    mongo.Connect();
                    IMongoDatabase db = mongo.GetDatabase("ecDoc");
                    GridFile fs = new GridFile(db, "ecDoc");
                    GridFileStream gfs = fs.OpenRead(filename);
                    byte[] bytes = new byte[gfs.Length];
                    gfs.Read(bytes, 0, bytes.Length);
                    return bytes;
                }
                catch (Exception ex)
                {
                    if (ex.GetType() == typeof(System.IO.DirectoryNotFoundException))
                        throw new System.IO.FileNotFoundException("File not found :" + filename);
                    else
                        throw ex;
                }
            }
        }
    }
}

不知道两个客户端的性能相比如何?希望测试过的同学分享一下。

posted @ 2011-01-20 23:07 Chris Cheung 阅读(695) 评论(0) 编辑

 

基于Mongodb的file server

 

最近在抱怨公司的file server,现有的file server通过服务器提供接口,将文件保存到服务器硬盘,按照ID分文件。通过定期备份到其它服务器,运行了这么久出现过一次事故,硬盘被同事格式化导致丢失了一部分数据。因此考虑如果重新设计file server我会怎么做,于是考虑使用Mongodb来设计,进行分布式同步。

 

 

使用Mongodb好处:

1.备份,维护简单

2.可以使用Mongodb的分布式同步数据,就算一台服务器挂了,fileserver也不会挂

3.速度会比较快(我猜)

 

file server 结构:

1. 使用webservice提供添加,删除,获取文件的接口,mongodb只保存文件内容

2. 将文件保存到Mongodb数据库

3. 存储文件由三个Mongodb数据库服务器组成,一个为Arbiter服务器,另外两个互为主从服务器

 

Mongodb服务器环境搭建:


1.下载最新版的mongodb for windows程序 http://www.mongodb.org/downloads

2.解压缩文件,重名名文件夹为mongodb,在mongodb文件夹下新建data,log文件夹,并复制两份为d:\mongodb2,d:\mongodb3

 

3.配置mongodb 1

在cmd命令定位到mongodb/bin文件夹,敲入下面命令启动mongodb:

D:\mongodb\bin>mongod --rest --replSet myset --port 20720 --dbpath d:\mongodb\data --logpath d:\mongodb\log

--replSet myset 指定mongodb运行为replication模式,集合名为myset

--rest 用于启动adminstration ui,可以通过http://localhost:28017/_replSet查看服务器状态

--dbpath 指定数据库文件路径

--logpath 指定日志文件路径

 

4.配置Mongodb 2

配置方法同mongodb 1,只是端口改为20721

D:\mongodb2\bin>mongod --rest --replSet myset --port 20721 --dbpath d:\mongodb2\data --logpath d:\mongodb\log

 

5.配置Mongodb 3

配置命令如下:

D:\mongodb2\bin>mongod --rest --replSet myset --oplogSize 8 --port 20722 --dbpath d:\mongodb3\data

 

具体解析查看http://www.mongodb.org/download/attachments/9830402/mongodb+replica+sets+intro.pdf

 

现在三台mongodb服务器都启动了,哦也,现在需要告诉Mongodb 1他的同伴Mongodb 2,具体命令如下:

D:\mongodb\bin>mongo --host ChrisCheung_PC//这里是我的计算机名,也可以是127.0.0.1 

首先执行

>rs.initiate()

>rs.add("ChrisCheung_PC:20721") //如果不知道计算机名可以用rs.conf()看到

{ "ok" : 1 }

 

这样就讲20721端口的mongodb添加到myset中,执行rs.conf()可查看相应信息。

 

接下来还要把Mongdb 3添加到组中,同意是在mongodb 1执行:

>rs.add( {_id:2, host:"ChrisCheung-PC:20722",arbiterOnly:true})

{ "ok" : 1 }

如果host打错会报下列错误:

 

{
"assertion" : "need most members up to reconfigure, not ok : ChrisCheung
-PC:20721",
"assertionCode" : 13144,
"errmsg" : "db assertion failure",
"ok" : 0
}

 

 

 

到目前位置我们已经有三台正常运行mongodb服务器,并配置为Replica Sets同步模式。

 

程序实现,下面是我写的一个简单类

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using MongoDB.Bson;

namespace FileUtility
{
    public class DocHelper
    {
        private string connStr = "";
        public string ConnStr
        {
            get 
            {
                if (string.IsNullOrEmpty(connStr))
                {
                    throw new ArgumentNullException("Connection string did not specify!");
                }
                return connStr;
            }
        }
        public DocHelper()
        {
            connStr = System.Configuration.ConfigurationManager.AppSettings["FileDb"];
        }

        public DocHelper(string connectionString)
        {
            this.connStr = connectionString;
        }

        /// <summary>
        /// save document conent
        /// </summary>
        /// <param name="content">file content</param>
        /// <returns>file id in mongodb database</returns>
        public string AddDoc(byte[] content)
        {
            MongoServer server = MongoServer.Create(this.ConnStr);
            try
            {
                Doc doc = new Doc() { ID = Guid.NewGuid().ToString(), data = content };
                server.Connect();
                MongoDatabase db = server.GetDatabase("ecDocs");
                MongoCollection<Doc> docs = db.GetCollection<Doc>("ecFiles",SafeMode.True);
                docs.Insert(doc);
                return doc.ID.ToString();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally 
            {
                if (server != null)
                    server.Disconnect();
            }
        }

        /// <summary>
        /// delete doc from the mongodb server
        /// </summary>
        public void DeleteDoc(string docID)
        {
            MongoServer server = MongoServer.Create(this.ConnStr);
            try
            {
                server.Connect();
                MongoDatabase db = server.GetDatabase("ecDocs");
                MongoCollection<Doc> docs = db.GetCollection<Doc>("ecFiles", SafeMode.True);
                var queryDoc = Query.EQ("_id", docID);
                docs.Remove(queryDoc);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (server != null)
                    server.Disconnect();
            }
        }
        /// <summary>
        /// get the doc content from mongodb
        /// </summary>
        /// <param name="docID">doc id in mongodb</param>
        /// <returns>document content</returns>
        public Doc GetDoc(string docID)
        {
            MongoServer server = MongoServer.Create(this.ConnStr);
            try
            {
                server.Connect();
                MongoDatabase db = server.GetDatabase("ecDocs");
                MongoCollection<Doc> docs = db.GetCollection<Doc>("ecFiles", SafeMode.True);
                Doc doc = docs.FindOneById(docID);
                return doc;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (server != null)
                    server.Disconnect();
            }
        }
    }
}

 

实体类:

 

using System;
using System.Collections.Generic;
using System.Text;
using MongoDB.Bson.DefaultSerializer;
using MongoDB.Bson;

namespace FileUtility
{
    public class Doc
    {
        [BsonId]
        public string ID { get; set; }
        public byte[] data { get; set; }
    }
}

 

测试代码:

 

代码
FileUtility.DocHelper helper = new FileUtility.cHelper("mongodb://localhost:20720");
byte[] bytes = File.ReadAllBytes("E:\\photo\\20110101-ski\\DSCN1621.JPG");
string id = helper.AddDoc(bytes);

FileUtility.Doc doc
= helper.GetDoc(id);
File.WriteAllBytes(
"d:\\image.jpg", doc.data);

 

 

插入一张图片后,到http://localhost:28017/_replSet  optime列的链接查看数据库的日志,可以看出两台服务器都插入了同样的记录,如下图:

 

 



好啦,一个简单的file server 就酱搭建起来了。简单插入一些数据,感觉mongodb暂用蛮大的硬盘空间,大家对file server有什么好的建议呢?欢迎拍砖,谢谢。


参考文章:

http://www.cnblogs.com/daizhj/archive/2010/09/08/1821481.html

http://www.cnblogs.com/daizhj/archive/2010/09/07/1820528.html

http://www.mongodb.org/

posted @ 2011-01-15 06:06 Chris Cheung 阅读(415) 评论(1) 编辑

之前写过关于UserControl的文章http://www.cnblogs.com/coolkiss/archive/2010/09/07/1820467.html

但是manager说UserControl复用性不好,于是改用WebControl了,改的过程遇到一些问题。

其中最主要的问题就是控件标签间 包含子控件,或者asp.net 页面变量的问题。

 

我希望实现的功能是,在控件间可以包含子控件

<cc:TitleEx runat="server">

<asp:Literal ID="litStr" runat="server"/>

</cc:TitleEx>

 

同时还要满足

<cc:TitleEx runat="server">

<%="hi"%>

</cc:TitleEx>

 

同时也可以这样使用:

<cc:TitleEx runat="server">

<% Response.Write("str");%>

</cc:TitleEx>

 

   [ParseChildren(false), PersistChildren(true), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class TitleEx : WebControl
    {
        public TitleEx()
            : base(HtmlTextWriterTag.Div)
        {
        }

        #region Attribute
        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string CssStyle
        {
            get
            {
                String s = (String)ViewState["CssStyle"];
                return ((s == null) ? String.Empty : s);
            }
            set
            {
                ViewState["CssStyle"] = value;
            }
        }

        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string CloseFunction
        {
            get
            {
                String s = (String)ViewState["CloseFunction"];
                return ((s == null) ? String.Empty : s);
            }
            set
            {
                ViewState["CloseFunction"] = value;
            }
        }

        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string DemoUrl
        {
            get
            {
                String s = (String)ViewState["DemoUrl"];
                return ((s == null) ? String.Empty : s);
            }
            set
            {
                ViewState["DemoUrl"] = value;
            }
        }


        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public string Text
        {
            get
            {
                String s = (String)ViewState["Text"];
                return ((s == null) ? String.Empty : s);
            }
            set
            {
                if (this.HasControls())
                {
                    this.Controls.Clear();
                }
                ViewState["Text"] = value;
            }
        }

        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string HelpUrl
        {
            get
            {
                String s = (String)ViewState["HelpUrl"];
                return ((s == null) ? String.Empty : s);
            }
            set
            {
                ViewState["HelpUrl"] = value;
            }
        }

        #endregion

        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            base.AddAttributesToRender(writer);
            writer.AddAttribute(HtmlTextWriterAttribute.Id, "divtitle");
            if (CssStyle != null)
            {
                string strStyle = CssStyle;
                writer.AddAttribute(HtmlTextWriterAttribute.Style, strStyle);
            }
        }

        public override void RenderBeginTag(HtmlTextWriter writer)
        {
            this.AddAttributesToRender(writer);
            HtmlTextWriterTag tagKey = this.TagKey;
            if (tagKey != HtmlTextWriterTag.Unknown)
            {
                writer.RenderBeginTag(tagKey);
                writer.Write(GetOutputHtmlBegin());
            }
            else
            {
                writer.RenderBeginTag(this.TagName);
            }
        }

        public override void RenderEndTag(HtmlTextWriter writer)
        {
            writer.Write(GetOutputHtmlEnd());
            base.RenderEndTag(writer);
        }

        #region get output html
        protected string GetOutputHtmlBegin()
        {
            StringBuilder sbHtml = new StringBuilder();
            sbHtml.AppendLine("<table width='100%' cellpadding=0 cellspacing=0 border=0 class='EMRTitle'>");
            sbHtml.AppendLine("<tr>");
            sbHtml.AppendLine("<td width='10%' align='left' class='EMRTitle'></td>");
            sbHtml.AppendLine("<td width='90%' align='left' class='EMRTitle'>");

            return sbHtml.ToString();
        }

        protected string GetOutputHtmlEnd()
        {
            StringBuilder sbHtml = new StringBuilder();
            sbHtml.Append("</td>");
            sbHtml.AppendLine("<td width=80 align='right' valign='top' nowrap>");
            if (!string.IsNullOrEmpty(DemoUrl) && DemoUrl.IndexOf("HTTP") == -1)
            {
                DemoUrl = "http://www.oooo.com/help/video/" + DemoUrl;
            }
            if (!string.IsNullOrEmpty(DemoUrl) && DemoUrl.Length > 0)
                sbHtml.AppendLine("<a href=\"javascript:\" onclick=\"javascript:pop('" + DemoUrl + "','',750,750);\">	<img src='https://img.oooo.com/ec/images/icon_viewdemo.gif' border=0 title='View Online Demo' style='visibility: visible;'/></a>");
            if (!string.IsNullOrEmpty(HelpUrl) && HelpUrl.Length > 0)
                sbHtml.AppendLine("<a href=\"javascript:\" onclick=\"javascript:pop('" + HelpUrl + "','',750,750);\">	<img src='https://img.oooo.com/ec/images/icon_help_small.gif' border=0 title='View help document' style='visibility: visible;'/></a>");

            if (!string.IsNullOrEmpty(CloseFunction) && CloseFunction.Length > 0)
            {
                sbHtml.AppendLine("  <a href=\"javascript:" + CloseFunction + "\"><img src='https://img.oooo.com/ec/images/button_close.gif' border=0 title='Close'></a>");
            }
            sbHtml.AppendLine("</td>");
            sbHtml.AppendLine("</tr>");
            sbHtml.AppendLine("</table>");
            return sbHtml.ToString();
        }
        #endregion
    }

posted @ 2010-12-30 11:40 Chris Cheung 阅读(55) 评论(0) 编辑
摘要: 前两天在codeproject看到一篇排序算法的文章sorting algorithms in C# ,看了今晚对仔细看了一下Cycle Sort,终于明白其中的原理:Cycle Sort(其实中文叫什么?)其实就是循环数组Arr每个元素,将当前元素Item放到最合适的位置,按升序的话,则计算小于Item的数据个数比如n,将item赋值给Arr[n]元素,同时,item被赋值为原有n位置上的值,继续循环,为item寻找合适位置,直到所有小于Item的个数都在合适的位置。然后取出所有Arr下一元素,继续上述的循环。下面是注释过的代码,看了好久才弄懂,自己mark一下,呵呵。调试中还发现,该算法对阅读全文
posted @ 2010-12-15 12:51 Chris Cheung 阅读(40) 评论(0) 编辑
摘要: 跨域名单点登录 part 1 --设计蓝图http://www.codeproject.com/KB/aspnet/CrossDomainSSOModel.aspx一个asp.net应用程序独立域名单点登录的解决方案。介绍"某个星期一的早上,你在办公室中感叹周末过得好快,而这周又会是多艰难的一周的时候。你收到一封邮件了,当然不是一份好工作offer,那只是你客户的另一个需求。你这个客户有好几个.n...阅读全文
posted @ 2010-09-10 10:44 Chris Cheung 阅读(129) 评论(0) 编辑
摘要: 关于用户自定义控件,想必大家已经非常熟悉了。虽然说经常用过,但是只是简单的使用而已。在这里再次总结一下Asp.net中的UserControl,以便下次使用时能够得心应手。本文将会介绍以下内容:1,什么是UserControl?2,如何定义一个UserControl?3,如何使用UserControl?4,如何通过UserControl属性来控制html?5,如何实现<u1:Control&...阅读全文
posted @ 2010-09-07 12:06 Chris Cheung 阅读(1056) 评论(2) 编辑
摘要: Garbage Collection Part 2: Automatic Memory Management in the Microsoft .NET FrameworkGC:.net framework中的自动内存管理Jeffrey Richter本文假设你已熟悉C和C++概要:本文的第一部分已经讲过了GC算法是如何工作的,当GC决定释放资源时是如何正确的回收内存的,以及如何强制释放一个fre...阅读全文
posted @ 2010-08-31 14:40 Chris Cheung 阅读(225) 评论(0) 编辑
摘要: 哈,又翻译了一篇文章,Jeffrey Richter的GC内存管理。呼,翻译真是不容易啊,利用工作空闲时间,翻译了好几天。Garbage Collection: Automatic Memory Management in the Microsoft .NET FrameworkGC:.net framework中的自动内存管理Jeffrey Richter本文假设你已熟悉C和C++概要 :.ne...阅读全文
posted @ 2010-08-27 14:31 Chris Cheung 阅读(226) 评论(0) 编辑