应用程序分类

做通用型软件没有出路,所以现在选择的是走按需订做的路子,这种方式的特点是归纳业务模式难、需求变化大、造价高。看在最后一点的面子上,不管想什么办法也得把合同签下。

程序分类的标准有很大,对于企业MIS来说,数据库是少不了的,根据企业的部署结构,分为本地和联网型:
一,本地型
此种类型指的是程序和数据库在同一台PC或者同一局域网(VPN也算),程序直接连接数据库,对数据库进行操作。
有些程序会允许多个客户端连接同一数据库,但一般情况各客户端对数据库的操作不会破坏数据完整性。

二,联网型
当本地型应用不能满足业务需求时,就要考虑联网型应用了。
1)纯在线型
此部署结构一般是指B/S结构,现阶段主流是Web应用。
它最大的特点是不需安装客户端,但同时也存在不能充分利用客户端PC资源的缺点。
编写此类型程序时,程序和数据库都处于服务器端。与本地型程序不同的是,它需要考虑并发状况。
另外需要特别指出的WPF的XBAP类型应用是一种伪在线型程序,它本质上还是本地型应用程序。

2)瘦客户端型
这种类型的应用程序可以弥补前两种类型的不足,这也意味着它更复杂、更高级。
一般来说,客户端只是对某一服务发出请求,并对结果进行呈现。服务端里封装了几乎所有的数据操作,并且对外提供服务。数据库一般都与服务端处于同一服务器或同一局域网。

售后调查系统

描述:
本软件提供企业售后调查记录功能。

授权:
本软件采用BSD授权。

技术:
架构采用.Net 4;
结构采用C/S;
UI采用WPF;
DAO采用NH3;
Logic层采用MVVM;
DB支持FireBird、PostgreSQL、MS SQL 2008。

截图:

扩展WPF的DataGrid如同Excel支持方向键移动焦点

WPF的DataGrid默认的移动行为如下:

(1)当前单元格不处于编辑状态时可使用方向键移动焦点。

(2)当前单元格处于编辑状态时不可使用方向键移动焦点;
按Enter键,当前单元格退出编辑状态,焦点向下移动一格;
按Ctrl+Enter键,当前单元格退出编辑状态,焦点向上移动一格;
按Tab键,当前单元格退出编辑状态,焦点向右移动一格,并进入编辑状态;
按Shift+Tab键,当前单元格退出编辑状态,焦点向左移动一格,并进入编辑状态;

“运营管理3.0″的用户普遍电脑操作水平低下,Office是它们操作的最多也是最智能的软件,它们认为所有的软件都必须是Office一样地操作,否则就给差评,所以它们要求”运营管理”的操作方式尽量与Excel相同.

为了实现WPF的DataGrid的移动方式与Excel相同,需要重写DataGrid的OnPreviewKeyDown事件:

public class ExDataGrid : DataGrid
    {
        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            if (e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up || e.Key == Key.Down)
            {
                try
                {
                    base.CommitEdit();
                }
                catch (Exception ex)
                {
                    base.CancelEdit();

                    string mess = ex.Message;
                    if (ex.InnerException != null)
                        mess += "nn" + ex.InnerException.Message;
                    MessageBox.Show(mess);
                }
            }

            base.OnPreviewKeyDown(e);
        }
    }

然后在使用DataGrid的地方换成已重写的ExDataGrid就可以了.

软件通过审核

软件名称: 运营管理系统
版         本: 3.0
开发语言: C# + WPF + SQL SERVER + .net 4.0 + NH2.1.2
运行结构: Browse Application
开发周期: 120天(coding)
总   代 码: 61000行
功        能: 商品管理
                   采购管理
                   销售管理
                   促销活动管理
                   顾客信息管理
                   现金、库存报表
                   通知管理
                   考勤打卡
                   权限管理
                   指纹验证
                   条码打印

WPF DataGrid神异的现象

一个WPF的DataGrid,绑定到一个集合List<MyClass>,模式为OneWay,从DataGrid里选择一行,传递到另个弹出页面,并绑定到TextBox等控件,模式为TwoWay,这个神异的现象是这样子的:

我添加了两条测试数据到List<MyClass>集合里,这时DataGrid显示两条记录,我选择第一条记录,传递到弹出页面显示,我在这里修改其中的任何数据,DataGrid的显示数据都不会随着修改而发生变化。

然而,当我在DataGrid里选择的是第二条记录,并传递到弹出页面显示,我在这里修改的任何数据,都会同步反映到DataGrid里。

我又尝试更换这两条记录的位置,还是编辑位于第一条的记录时不能同步。

有个页面的DataGrid,只有第三条记录能同步显示,其余记录在修改时均不能同步显示。

有两个页面的DataGrid所有记录都能同步显示。

另外,即使不能同步显示,但DataGrid里记录的值其实是修改后的值。

封装了Popup

代码如下:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Threading;

namespace Yuzifu.Tools
{
    public sealed class MessagePopup
    {
        public static void Show(UIElement parent, string message)
        {
            parent.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =&gt;
                {
                    Popup popup = new Popup();
                    popup.StaysOpen = true;
                    popup.PlacementTarget = parent;
                    popup.Placement = PlacementMode.Center;

                    Border aroundBorder = new Border();
                    aroundBorder.BorderThickness = new Thickness(2);
                    aroundBorder.BorderBrush = Brushes.SteelBlue;

                    StackPanel aroundStackPanel = new StackPanel();
                    aroundStackPanel.MinWidth = 320;
                    aroundStackPanel.MinHeight = 120;
                    aroundStackPanel.MaxWidth = 480;
                    aroundStackPanel.Background = Brushes.White;
                    aroundStackPanel.Orientation = Orientation.Vertical;
                    aroundStackPanel.FlowDirection = FlowDirection.LeftToRight;

                    DockPanel headDockPanel = new DockPanel();
                    headDockPanel.VerticalAlignment = VerticalAlignment.Top;
                    headDockPanel.Background = Brushes.SteelBlue;

                    TextBlock headTextBlock = new TextBlock();
                    headTextBlock.Margin = new Thickness(10, 0, 0, 0);
                    headTextBlock.Text = "提示";
                    headTextBlock.Height = 26;
                    headTextBlock.HorizontalAlignment = HorizontalAlignment.Left;
                    headTextBlock.VerticalAlignment = VerticalAlignment.Center;
                    headTextBlock.FontSize = 16;
                    headTextBlock.Focusable = false;
                    headTextBlock.IsHitTestVisible = false;
                    headTextBlock.Background = Brushes.SteelBlue;
                    headTextBlock.Foreground = Brushes.White;

                    TextBlock messageTextBlock = new TextBlock();
                    messageTextBlock.Text = message;
                    messageTextBlock.Margin = new Thickness(20, 20, 20, 10);
                    messageTextBlock.MinHeight = 28;
                    messageTextBlock.VerticalAlignment = VerticalAlignment.Top;
                    messageTextBlock.HorizontalAlignment = HorizontalAlignment.Left;
                    messageTextBlock.TextWrapping = TextWrapping.Wrap;

                    Button okButton = new Button();
                    okButton.Content = "OK";
                    okButton.Margin = new Thickness(0, 0, 20, 10);
                    okButton.Padding = new Thickness(25, 3,25,3);
                    okButton.HorizontalAlignment = HorizontalAlignment.Right;
                    okButton.Click += delegate
                    {
                        popup.IsOpen = false;
                        parent.IsEnabled = true;
                    };

                    headDockPanel.Children.Add(headTextBlock);
                    aroundStackPanel.Children.Add(headDockPanel);
                    aroundStackPanel.Children.Add(messageTextBlock);
                    aroundStackPanel.Children.Add(okButton);
                    aroundBorder.Child = aroundStackPanel;
                    popup.Child = aroundBorder;

                    parent.IsEnabled = false;
                    popup.IsOpen = true;
                }));
        }
    }
}

使用方法:

MessagePopup.Show(this,”显示文字”);

显示效果如下:

WPF多线程以及UI

一、界面无响应,即所谓的卡

可以使用
delegate void DeleDisp();
DeleDisp dd = new DeleDisp(DispInfo);
dd.BeginInvoke(null, null);

如果使用了
Dispatcher.BeginInvoke(dd);
则界面依然会卡

二、报异常“控件由其它线程创建,无法访问其它线程的UI”

这个比较简单
只要使用把访问UI属性的代码用
Dispatcher.BeginInvoke()
包装起来就可以了。

如果是循环更改界面,则应该把把循环的代码放在Dispatcher.BeginInvoke()外面。

三、控件不能同步显示

如果出现这种现象,既可以调用控件的
Refresh()
方法来刷新,

还可以调用
System.Windows.Forms.Application.DoEvents()
方法来刷新。

2009-10-11 tips

1,项目上线了,版本为2009.0 beta

2,试用了好几个开源OA,最满意的是Group-Office,不过还没法用它,它的在线编辑文档功能是付费才有的

3,实施是一门艺术

4,OpenVPN比PPTP好用的地方在于,同一局域网里可以多个客户端同时拔号

5,WPF看起来不错,界面跟逻辑分开,很清楚,虽然JAVA也可以,但JAVA的开发效率实在不怎么样

6,国庆花了几个下午,把天下2的角色升到了45级

7,体重降了一点点,71.5KG

8,月底休假