dcll

千古功过唯一晓,纵是留影也点灯

导航

公告

随笔档案

最新评论

统计

常用链接

阅读排行榜

评论排行榜

2010年8月22日 #

WPF:ToolBar Button设置图片

 

WPF中ToolBar,可以放置Button。但是,默认的Button上是没有图片的。

网上找了很久,有说明如何放置图片的,但是只有图片,没有文字。

现在发现,原来图片文字都显示如此简单,XAML代码参考如下。

        <ToolBar Grid.Row="0"  Name="tlbMain" >
            <!--Content="保存"-->
            <Button   Name="btnSave" Command="my:SunLightGridCommands.Save">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition>
                            
                        </RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                <Image Source="/SunLight.Client.Common;component/Images/install.ico"></Image>
                    <TextBlock Text="保存" Grid.Row="1"></TextBlock>
                </Grid>
            </Button>

实际上就是设置了一下,Button的Content。通过Grid,还可以设置在左右显示等等。

在此记录一下,感觉WPF很多概念真是颠覆性的。

 

posted @ 2010-08-22 22:30 dcll 阅读(2746) 评论(0) 编辑

2010年7月25日 #

语法糖

先介绍一个例子,如下两个表格数据:

左边表格
ItemCode 属性值1 属性值2 属性值3
A 20 30 40
B 30 30 44
C 25 30 44
D 34 30 60
右边表格
ItemCode 分类 属性值1 属性值2 属性值3
A 0 90 90 90
B 1 90 90 90
D 2 90 90 90
E 2 90 90 90

需求说明如下:

  1. 【分类】 列的值 有三种类型 0、1、2
  2. ItemCode是唯一的,在表格中不会重复
  3. 将左边的数据,按照ItemCode,复制到右边表格

          如果左右两边都有ItemCode,检查分类值,如果对应的分类值是0:则不复制。

                                                    如果分类值是1:则修改属性值1

                                                    如果分类值是2:则修改属性值 1- 3

   如果仅在右边的表格没有的数据,则把分类值修改成0,属性值不修改

   如果仅在左边的表格有的数据,则右边新增一条,分类值是2,属性值1-3复制过来

如上例子,复制后的结果如下:

ItemCode 分类 属性值1 属性值2 属性值3
A(不变) 0 90 90 90
B(修改1) 1 30 90 90
D(修改1-3) 2 34 30 60
E(仅右边) 0 90 90 90
C(仅左边) 2 25 30 44
 
针对上述要求,程序实现可能如下:
 
 public void CopyData(DataTable leftTable, DataTable rightTable)
        {
            //找出在仅在右边存在或者都存在的数据
            foreach (DataRow row in rightTable.Rows)
            {
                string itemCode = row["ItemCode"] as string;
                DataRow[] rows = leftTable.Select("ItemCode = '" + itemCode + "'");
                if (rows.Length == 0)
                {
                    //仅修改分类值
                    row["分类"] = 0;
                }
                else
                {
                    //左右都存在
                    int type = (int)row["分类"];
                    if (type > 0)
                    {
                        row["属性值1"] = row["属性值1"];
                        if (type == 2)
                        {
                            row["属性值2"] = row["属性值2"];
                            row["属性值3"] = row["属性值3"];
                        }
                    }
                }
            }

            //找出仅在左边存在数据
            foreach (DataRow row in leftTable.Rows)
            {
                string itemCode = row["ItemCode"] as string;
                DataRow[] rows = rightTable.Select("ItemCode = '" + itemCode + "'");
                if (rows.Length == 0)
                {
                    //在右边新增一条
                    DataRow newRow = rightTable.NewRow();
                    newRow["分类"] = 2; //分类值是2
                    newRow["ItemCode"] = itemCode;
                    newRow["属性值1"] = row["属性值1"];
                    newRow["属性值2"] = row["属性值2"];
                    newRow["属性值3"] = row["属性值3"];
                    rightTable.Rows.Add(newRow);
                }
                else
                {
                    //左右都存在
                    //什么也不做
                }
            }
        }
 
 

上面的代码应该算是清晰的。而且有了足够的注释,不算很难读懂。

但是,这个代码和业务逻辑描述的是一致的吗?换句话说:如果没有需求文档,单单看上面代码,能得到上面的总结的需求吗?

我觉得要整理出上面需求比较难,理由如下。

针对第一个问题,似乎很好解决。可以定义一个枚举类型来描述分类值就可以了,如下:

        public enum Enu分类
        {
            不改变 = 0,
            仅改变1 = 1,
            全部改变 = 2
        }

 

相应的代码可以修改成这样

                if (rows.Length == 0)
                {
                    //仅修改分类值
                    row["分类"] =(int) Enu分类.不改变;
                }
                else
                {
                    //左右都存在
                    Enu分类 type = (Enu分类)row["分类"];
                    switch(type)
                    {
                        case Enu分类.全部改变:
                            row["属性值1"] = row["属性值1"];
                            row["属性值2"] = row["属性值2"];
                            row["属性值3"] = row["属性值3"];
                            break;
                        case Enu分类.仅改变1:
                           row["属性值1"] = row["属性值1"];
                            break;
                        case Enu分类.不改变:
                            break;
                    }
                }
 
但是,对于第2个问题,则比较复杂了。如果和能像需求说明那样简洁的实现呢?
仔细分析,实际上需求说明中表述两个两层意思:
1、对比左右两个表格,得到都存在的、仅左边、仅右边结果
2、三种数据处理方式如下:
   1)、都存在的处理方式按照分类
   2)、仅左边的,则在右边新增一行
   3)、仅右边的,则修改分类为0

    那么另外一种实现方式是

       1、做一个DataTable对比类,得到三种类型数据

       2、遍历这三种数据即可。

   实现方式如下:

  public void CopyData2(DataTable leftTable, DataTable rightTable)
        {
            DataTableComparer cmp = new DataTableComparer(leftTable, rightTable, "ItemCode");
            foreach(CompareResult result in cmp.Rows)
            {
                switch (result.Type)
                {
                    case ResultType.Both:
                        //左右都存在
                        Enu分类 type = (Enu分类)result.RightRow["分类"];
                        switch (type)
                        {
                            case Enu分类.全部改变:
                                result.RightRow["属性值1"] = result.LeftRow["属性值1"];
                                result.RightRow["属性值2"] = result.LeftRow["属性值2"];
                                result.RightRow["属性值3"] = result.LeftRow["属性值3"];
                                break;
                            case Enu分类.仅改变1:
                                result.RightRow["属性值1"] = result.LeftRow["属性值1"];
                                break;
                            case Enu分类.不改变:
                                break;
                        }
                        break;
                    case ResultType.LeftOnly:
                        DataRow newRow = rightTable.NewRow();
                        newRow["分类"] = Enu分类.全部改变;
                        newRow["ItemCode"] = result.LeftRow["ItemCode"];
                        newRow["属性值1"] = result.LeftRow["属性值1"];
                        newRow["属性值2"] = result.LeftRow["属性值2"];
                        newRow["属性值3"] = result.LeftRow["属性值3"];
                        rightTable.Rows.Add(newRow);
                        break;
                    case ResultType.RightOnly:
                        //仅修改分类值
                        result.RightRow["分类"] = (int)Enu分类.不改变;
                        break;
                }
            }
        }

 

TableComparer类实现如下:

 class DataTableComparer
    {

        public DataTableComparer(DataTable left, DataTable right, params string[] keys)
        {
            m_rows = CreateAllRows(left.Rows, right.Rows, keys);
        }

        private string GetKey(DataRow row, string[] keys)
        {
            StringBuilder sb = new StringBuilder();
            foreach (string key in keys)
            {
                sb.Append(Convert.ToString(row[key]) + "|");

            }
            return sb.ToString();
        }
        private Dictionary<string, CompareResult> CreateAllRows(IEnumerable leftRows, IEnumerable rightRows, string[] keys)
        {
            Dictionary<string, CompareResult> rows = new Dictionary<string, CompareResult>();
            foreach (DataRow row in leftRows)
            {
                string key = GetKey(row, keys);
                CompareResult result = new CompareResult();
                result.LeftRow = row;
                result.Type = ResultType.LeftOnly;
                rows.Add(key, result);
            }

            foreach (DataRow row in rightRows)
            {
                string key = GetKey(row, keys);
                if (rows.ContainsKey(key))
                {
                    CompareResult result = rows[key];
                    result.Type = ResultType.Both;
                    result.RightRow = row;
                }
                else
                {
                    CompareResult result = new CompareResult();
                    result.RightRow = row;
                    result.Type = ResultType.RightOnly;
                    rows.Add(key, result);
                }
            }

            return rows;
        }
        private Dictionary<string, CompareResult> m_rows;

        public IEnumerable<CompareResult> Rows
        {
            get
            {
                foreach (KeyValuePair<string, CompareResult> keyValue in m_rows)
                {
                    yield return keyValue.Value;

                }
            }
        }

    }

    public class CompareResult
    {
        public ResultType Type;
        public DataRow LeftRow;
        public DataRow RightRow;
    }

    public enum ResultType
    {
        Both,
        LeftOnly,
        RightOnly,

    }

 

 

结论:

  1.   软件代码中的注释对代码维护工作非常重要。但是,结构良好,更接近于自然语言描述的代码更重要。甚至,有时候可以替代注释的效果。
  2. 软件需求在转换为软件代码过程中,仍然有值得仔细推敲,整理的必要,这样才能保证在实现过程中,尽量与软件需求描述一致。
  3. 当然,上述代码中,第二种方案有时候也未必是最优的。如果考虑性能的话,大数据量的dataTable,可能第一种方案还是可取的。
  4. 以上没有使用Linq去实现,如果用到Linq的话,代码应该还可以简化。

posted @ 2010-07-25 16:16 dcll 阅读(236) 评论(0) 编辑

2010年5月12日 #

学习使用Live Writer写博客

刚刚下载了Live Writer,据说使用该动动写博客比较方便。试验一下看看。

标题 标题2
   

posted @ 2010-05-12 21:32 dcll 阅读(9) 评论(1) 编辑

2010年5月10日 #

也谈需求变化的应对

看到很多人太需求变化,我也谈一下,凑个热闹。

 举个例子:

          比如有一个程序要用combox显示一个列表。列表内容是X1、X2、X3。程序中会根据X1,X2,X3判断做一些处理。

参考代码如下:

  

代码

  
int value = comboBox1.SelectedIndex;
            
switch (value)
            {
                
case 0:
                    MessageBox.Show(
"x1");
                    
break;
                
case 1:
                    MessageBox.Show(
"x2");
                    
break;
                
case 2:
                    MessageBox.Show(
"x3");
                    
break;

            }

 

 

用户使用过一段时间后,需要增加列表内容:比如增加X4,X5。那么上述程序就要改成:

 

代码
  int value = comboBox1.SelectedIndex;
            
switch (value)
            {
                
case 0:
                    MessageBox.Show(
"x1");
                    
break;
                
case 1:
                    MessageBox.Show(
"x2");
                    
break;
                
case 2:
                    MessageBox.Show(
"x3");
                    
break;
                
//v2.0 add 支持x4,x5
                case 3:
                    MessageBox.Show(
"x4");
                    
break;
                
case 4:
                    MessageBox.Show(
"x5");
                    
break;
            }

 

维护代码,风格好点的会写点注释。

这样的方式可以一直延续下去,用户不断增加需求,程序员不断修改代码。但是,有没有更好的方案呢?我相信博客园的高手众多,肯定又很多很好的方案。我想的方案是这样的:

  

代码
  public partial class Form1 : Form
    {
        
public Form1()
        {
            InitializeComponent();

            List
<ObjectHolder> list = new List<ObjectHolder>();
            list.Add(
new ObjectHolder(0,"test1"));
            list.Add(
new ObjectHolder(0,"test1"));
            list.Add(
new ObjectHolder(0,"test1"));

            comboBox1.DataSource 
= list;
        }

        
private void button1_Click(object sender, EventArgs e)
        {
            
//int value = comboBox1.SelectedIndex;
            
//switch (value)
            
//{
            
//    case 0:
            
//        MessageBox.Show("x1");
            
//        break;
            
//    case 1:
            
//        MessageBox.Show("x2");
            
//        break;
            
//    case 2:
            
//        MessageBox.Show("x3");
            
//        break;
            
//    //v2.0 add 支持x4,x5
            
//    case 3:
            
//        MessageBox.Show("x4");
            
//        break;
            
//    case 4:
            
//        MessageBox.Show("x5");
            
//        break;
            
//}
            
// V3.0 重构
            ObjectHolder selectObject = comboBox1.SelectedItem as ObjectHolder;
            selectObject.DoWork();

        }
    }

    
class ObjectHolder
    {
        
public int value;
        
public string caption;

        
public ObjectHolder(int value, string caption)
        {
            
this.value = value;
            
this.caption = caption;
        }

        
public override string ToString()
        {
            
return caption;
        }

        
public void DoWork()
        {
            MessageBox.Show(
this.caption);
        }
    }

 

 

引入对象的方法来解决。将来如果变化仍然频繁,可以考虑把combox列表配置成外部文件,如:XML。Table等等。

 

说了这么多,我觉得就是敏捷里面的一个核心思想,拥抱变化。通过重构来不断进化你的程序架构。这样,始终保持你的程序健壮性。又不至于过度设计。

当然,上面的例子可能有些过于简单,第一个版本就设计成对象的方式也未尝不可。只是,如果复杂的例子,能够经历过这样的演进过程会让程序变化更平稳。

posted @ 2010-05-10 20:48 dcll 阅读(46) 评论(0) 编辑

2010年3月23日 #

博士生与民工的笑话

看过一个博士生与民工的笑话:

联合利华引进了一条香皂包装生产线,结果发现这条生产线有个缺陷:常常会有盒子里
没装入香皂。总不能把空盒子卖给顾客啊,他们只得请了一个学自动化的博士后设计一
个方案来分拣空的香皂盒。博士后拉起了一个十几人的科研攻关小组,综合采用了机械
、微电子、自动化、X射线探测等技术,花了几十万,成功解决了问题。每当生产线上
有空香皂盒通过,两旁的探测器会检测到,并且驱动一只机械手把空皂盒推走。 

中国南方有个乡镇企业也买了同样的生产线,老板发现这个问题后大为发火,找了个小
工来说:“你他妈给老子把这个搞定,不然你给老子爬走。”小工很快想出了办法:他
花了90块钱在生产线旁边放了一台大功率电风扇猛吹,于是空皂盒都被吹走了。

这个故事对于从软件开发角度理解:我觉得是简单就是美。我们往往容易被自己的知识束缚,

往往会把本来简单的事情想复杂化了。或者,有时候过于迷恋技术,而往往忘了一个本来要解决的问题。

所以,考虑问题的时候,有时候可以先问问自己,有没有简单的方法? 而不是先想到可以

用哪些很酷的技术。

posted @ 2010-03-23 22:26 dcll 阅读(166) 评论(6) 编辑

2004年9月7日 #

COM+ Performace

摘要: 前几天做了关于COM+的性能测试,http://www.cnblogs.com/dcll/archive/2004/08/30/37530.aspx,结果因为表格太长,被dudu屏蔽了。今天偶然在CodeProject上看到一篇文章也提到了COM+的性能问题,http://www.codeproject.com/dotnet/complusnetpracticalapp01.asp其中涉及到性能数...阅读全文

posted @ 2004-09-07 22:21 dcll 阅读(814) 评论(0) 编辑

2004年8月30日 #

请问.NET如何实现分布式系统?

摘要: 我希望实现一个分布式系统,要求可以通过Internet/Intranet访问。但是,不希望用WEB实现,因为web页面的处理能力有限。.NET中该选什么技术?Remoting ? COM+?,请各位高手指点。或者谈谈各位在工作怎么做的?谢谢。阅读全文

posted @ 2004-08-30 19:55 dcll 阅读(735) 评论(0) 编辑

COM Plus 调用与.NET Remote调用性能对比

摘要: 这两天在研究.NET分布式应用方案,我对.NET不是很了解,只知道就是三种方式可以实现分布式应用:COM+,.NET Remoting,Web Service。感觉.NET Remoting提供很大灵活性,支持tcp,http协议。而且,基于性能上也考虑两种序列化方式binary和Soap方式。要比较那种方式好,要分几个方面,目前做了COM+,.NET Remoting调用性能对比。对比方法:分别...阅读全文

posted @ 2004-08-30 00:11 dcll 阅读(1573) 评论(4) 编辑

仅列出标题