MDI程序其中一个子窗体改变数据库,怎样让其他子窗体知道呢?
RT;
做进销存系统的时候,客户一般喜欢把库存子窗口和销售子窗口等等打开,这样最好能在销售窗口做销售时,库存窗口的数据及时变化。(PS:不止这两个窗口需要,类似的情况很多)
[解决办法]
你可以参考设计模式中的观察者模式,最适合解决你的这个问题,所有子窗口注册成为观察者,一旦某个子窗口更改了数据库,就像观察者消息中心发送一个数据更新消息,中心把这个消息转发给其他注册的观察者,其他观察者就可以更改界面,
[解决办法]
{
ReLoad(tracker, dataType);
}
}
}
}
}
/// <summary>
/// 判断并刷新指定的跟踪对象
/// </summary>
/// <param name="tracker"></param>
public static void ReLoad(ITracker tracker)
{
if (componetsToReload[tracker])
{
tracker.ReLoad();
componetsToReload[tracker] = false;
}
}
/// <summary>
/// 判断并刷新指定的跟踪对象
/// </summary>
/// <param name="tracker"></param>
/// <param name="typeName"></param>
public static void ReLoad(INamedTracker tracker, string typeName)
{
List<string> trackTypes = tracker.TrackTypes.Split(',').ToList();
string reloadNames = namesToReload[tracker];
string pattern = "\\W*" + typeName + "\\W*";
if (trackTypes.Contains(typeName) && Regex.IsMatch(reloadNames, pattern))
{
tracker.ReLoad(typeName);
namesToReload[tracker] = Regex.Replace(reloadNames, pattern, ",");
}
}
/// <summary>
/// 注册跟踪对象
/// </summary>
/// <param name="tracker"></param>
public static void Register(ITracker tracker)
{
if (tracker is INamedTracker && !namesToReload.ContainsKey(tracker))
{
namesToReload.Add(tracker, "");
}
else if (!componetsToReload.ContainsKey(tracker))
{
componetsToReload.Add(tracker, false);
}
}
/// <summary>
/// 反注册跟踪对象
/// </summary>
/// <param name="tracker"></param>
public static void UnRegister(ITracker tracker)
{
if (componetsToReload.ContainsKey(tracker))
{
componetsToReload.Remove(tracker);
}
if (namesToReload.ContainsKey(tracker))
{
namesToReload.Remove(tracker);
}
}
}
3. 设计一个基类窗体继承自ITracker接口,其他需要刷新的窗体继承自这个基窗体:
------------------------------
public partial class FormBase : Form, ITracker
{
/// <summary>
/// 指定窗体是否在收到数据改变通知时是否立即刷新 王家新
/// </summary>
public bool FastReload { get; set; }
//在此定义窗体数据刷新的方法
public virtual void ReLoad(){
}
//需要监视刷新的数据源名称
public virtual string TrackTypes { get {return "数据源名称"; }
/// <summary>
/// 构造函数,用于初始化窗体对象
/// </summary>
public FormBase()
{
// 初始化窗体控件
InitializeComponent();
//如果继承Iracker接口,则代替子类注册到DataTracker中
ITracker tracker = this as ITracker;
if (tracker == null) return;
DataTracker.Register(tracker);
bool firstload = true;
//在窗体被激活时,判断是否需要刷新数据
((Form)tracker).Activated += (s, e) =>
{
if (!firstload)
{
if (tracker is INamedTracker)
{
foreach (string dataType in tracker.TrackTypes.Split(','))
{
DataTracker.ReLoad((INamedTracker)tracker, dataType);
}
}
else
{
DataTracker.ReLoad(tracker);
}
}
else
{
firstload = false;
}
};
((Form)tracker).FormClosed += (s, e) =>
{
DataTracker.UnRegister(tracker);
};
}
}
4. 在发起数据更新通知的窗体内写以下方法:
-----------------------
//更新数据,然后:
DataTracker.Change("数据源名称,它和接收更新的窗体中定义的同名");
说明:
当然这是一种单机模式的联动。如果要求分布式的联动,可以将DataTraker重构成用某个网络服务来执行Changed事件,这是不难的。
我自以为这种方法比起传统观察者模式的好处是观察者和被观察者都不需要知道对方的存在。双方的协议也非常简单,只需要知道相同的数据源名称即可。而且名称是随便由你起的,用你女朋友的名字都可以。