使用 winform 实现观察者模式
我有一个对象集合,我的许多表单(使用 WeifenLuo.WinFormsUI.Docking)需要与之交互。
即,如果集合在一种表单中进行了添加(或删除),则其他表单通过刷新其视图来响应。
显然,观察者模式在这里是一个不错的选择。但是,我在尝试在我的程序中实现这一点时遇到了问题。
首先,似乎最好为我的集合创建一个观察者类,如下所示:
public class DataCollectionObserver : Form
{
internal static void DataCollectionRegister(DataCollection dataCollection)
{
dataCollection.ImageAdded += new EventHandler(dataAdded);
dataCollection.ImageRemoved += new EventHandler(dataRemoved);
dataCollection.ImageIndexChanged += new EventHandler(dataIndexChanged);
dataCollection.ImageListCleared += new EventHandler(dataListCleared);
}
internal static void DataCollectionUnRegister(DataCollection dataCollection)
{
dataCollection.ImageAdded -= new EventHandler(dataAdded);
dataCollection.ImageRemoved -= new EventHandler(dataRemoved);
dataCollection.ImageIndexChanged -= new EventHandler(dataIndexChanged);
dataCollection.ImageListCleared -= new EventHandler(dataListCleared);
}
internal static void dataAdded(object sender, EventArgs e) {}
internal static void dataRemoved(object sender, EventArgs e) {}
internal static void dataIndexChanged(object sender, EventArgs e) {}
internal static void dataListCleared(object sender, EventArgs e) {}
}
然后重写子类表单中的基本事件处理程序?
但是,我不能这样做并使用 WeifenLuo.WinFormsUI.Docking 库...
好吧,我可以让 DataCollectionObserver 从 WeifenLuo.WinFormsUI.Docking 继承 DockContent,但这会产生一种情况,我需要有两个 DataCollectionObserver 类 - 一个继承 Form ,另一个继承 DockContent :-[ 或者,我可以使 DataCollectionObserver 成为一个接口,但这仍然让我留下重复的代码......
那么,有人在这里有建议吗?我是否遗漏了一些明显的东西,或者这是为了简单起见“必须完成”重复代码的情况?
Edit://
我在表单中获取通知时没有遇到问题。事实上,现在一切都在进行中。我问的原因是,由于我订阅集合事件并在 Form.Closing() 上取消订阅的这四种不同表单中的代码块复制和粘贴,整个事情“闻起来”。
我想要做的是实现我已复制并粘贴到这四个表单中的行为,并让应接收集合更改通知的表单根据需要实现该行为。
希望这能让事情变得更清楚吗?
FWIW,这是我的收藏类:
using System;
using System.Collections;
using System.Reflection;
namespace MyNameSpace.Collections
{
/// <summary>
/// Generic Collection of Objects with Events
/// </summary>
public class CollectionWithEvents<T> : CollectionBase
{
public bool SuppressEventNotification
{
get;
set;
}
public CollectionWithEvents()
{
SuppressEventNotification = false;
}
#region Events
/// <summary>
/// Raises before an item is added to the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> BeforeItemAdded;
/// <summary>
/// Raises when an item is added to the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> ItemAdded;
/// <summary>
/// Raises before a collection of items is added to the list.
/// </summary>
public event EventHandler<ItemsEventArgs<T>> BeforeItemsAdded;
/// <summary>
/// Raises when a collection of items is added to the list.
/// </summary>
public event EventHandler<ItemsEventArgs<T>> ItemsAdded;
/// <summary>
/// Raises before an item is changed in the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> BeforeItemChanged;
/// <summary>
/// Raises when an item is changed in the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> ItemChanged;
/// <summary>
/// Raises before an item is removed from the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> BeforeItemRemoved;
/// <summary>
/// Raises when an item is removed from the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> ItemRemoved;
/// <summary>
/// Raises when the items are cleared from the list.
/// </summary>
public event EventHandler<EventArgs> ItemsCleared;
#endregion
public T this[int index]
{
get { return (T)this.List[index]; }
set
{
if (!SuppressEventNotification)
{
OnBeforeItemChanged(this, new ItemEventArgs<T>(value));
}
this.List[index] = value;
if (!SuppressEventNotification)
{
OnItemChanged(this, new ItemEventArgs<T>(value));
}
}
}
public int Add(T item)
{
if (!SuppressEventNotification)
{
OnBeforeItemAdded(this, new ItemEventArgs<T>(item));
}
int retValue = this.List.Add(item);
if (!SuppressEventNotification)
{
OnItemAdded(this, new ItemEventArgs<T>(item));
}
return retValue;
}
public void AddRange(Collection<T> collection)
{
T[] tmp = new T[collection.Count];
collection.CopyTo(tmp, 0);
AddRange(tmp);
}
public void AddRange(T[] collection)
{
if (!SuppressEventNotification)
{
OnBeforeItemsAdded(this, new ItemsEventArgs<T>(collection));
}
this.AddRange(collection);
if (!SuppressEventNotification)
{
OnItemsAdded(this, new ItemsEventArgs<T>(collection));
}
}
public bool Contains(T item)
{
return this.List.Contains(item);
}
public void CopyTo(Array array, int index)
{
this.List.CopyTo(array, index);
}
public int IndexOf(T item)
{
return this.List.IndexOf(item);
}
public void Insert(int index, T item)
{
this.List.Insert(index, item);
}
public void Remove(T item)
{
if (!SuppressEventNotification)
{
OnBeforeItemRemoved(this, new ItemEventArgs<T>(item));
}
T tmp = (T)item;
this.List.Remove(item);
if (!SuppressEventNotification)
{
OnItemRemoved(this, new ItemEventArgs<T>(tmp));
}
tmp = default(T);
}
public void Sort(string Property, Common.SortOrder Order)
{
Common.GenericComparer genericComparer = new Common.GenericComparer(Property, Order);
this.InnerList.Sort(genericComparer);
}
#region Event Methods
/// <summary>
/// Raised before an Item is added to the list.
/// </summary>
/// <param name="sender">object</param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnBeforeItemAdded(object sender, ItemEventArgs<T> e)
{
if (BeforeItemAdded != null)
{
BeforeItemAdded(sender, e);
}
}
/// <summary>
/// Raised when an Item is added to the list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnItemAdded(object sender, ItemEventArgs<T> e)
{
if (ItemAdded != null)
{
ItemAdded(sender, e);
}
}
/// <summary>
/// Raised before a collection of Items is added to the list.
/// </summary>
/// <param name="sender">object</param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnBeforeItemsAdded(object sender, ItemsEventArgs<T> e)
{
if (BeforeItemsAdded != null)
{
BeforeItemsAdded(sender, e);
}
}
/// <summary>
/// Raised when a collection of Items is added to the list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnItemsAdded(object sender, ItemsEventArgs<T> e)
{
if (ItemsAdded != null)
{
ItemsAdded(sender, e);
}
}
/// <summary>
/// Raised before an Item is changed to the list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">GenericItemEventArgs</param>
protected virtual void OnBeforeItemChanged(object sender, ItemEventArgs<T> e)
{
if (BeforeItemChanged != null)
{
BeforeItemChanged(sender, e);
}
}
/// <summary>
/// Raised when an Item is changed to the list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnItemChanged(object sender, ItemEventArgs<T> e)
{
if (ItemChanged != null)
{
ItemChanged(sender, e);
}
}
/// <summary>
/// Raised before an Item is removed from the list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnBeforeItemRemoved(object sender, ItemEventArgs<T> e)
{
if (BeforeItemRemoved != null)
{
BeforeItemRemoved(sender, e);
}
}
/// <summary>
/// Raised when an Item is removed from the list.
/// </summary>
/// <param name="sender">object</param>
/// <param name="e">ItemEventsArgs</param>
protected virtual void OnItemRemoved(object sender, ItemEventArgs<T> e)
{
if (ItemRemoved != null)
{
ItemRemoved(sender, e);
}
}
/// <summary>
/// Raised when the Items are cleared from this list.
/// </summary>
/// <param name="sender">object</param>
/// <param name="e">EventArgs</param>
protected virtual void OnItemsCleared(object sender, EventArgs e)
{
if (ItemsCleared != null)
{
ItemsCleared(sender, e);
}
}
#endregion
}
public class ItemEventArgs<T> : EventArgs
{
/// <summary>
/// Item
/// </summary>
public T Item { get; private set; }
/// <summary>
/// Default constructor
/// </summary>
/// <param name="Item"></param>
public ItemEventArgs(T Item)
{
this.Item = Item;
}
}
public class ItemsEventArgs<T> : EventArgs
{
/// <summary>
/// Items
/// </summary>
public T[] Items { get; private set; }
/// <summary>
/// Default constructor
/// </summary>
/// <param name="Items"></param>
public ItemsEventArgs(T[] Items)
{
this.Items = Items;
}
}
}
I have one collection of objects that many of my forms (using WeifenLuo.WinFormsUI.Docking) need to interact with.
i.e. If the collection has an addition (or deletion) made in one form, then the other forms respond by refreshing their views.
Obviously, an observer pattern would be a good candidate here. However, I am having issues trying to implement this in my program.
First, it seemed best to create an observer class for my collection like so:
public class DataCollectionObserver : Form
{
internal static void DataCollectionRegister(DataCollection dataCollection)
{
dataCollection.ImageAdded += new EventHandler(dataAdded);
dataCollection.ImageRemoved += new EventHandler(dataRemoved);
dataCollection.ImageIndexChanged += new EventHandler(dataIndexChanged);
dataCollection.ImageListCleared += new EventHandler(dataListCleared);
}
internal static void DataCollectionUnRegister(DataCollection dataCollection)
{
dataCollection.ImageAdded -= new EventHandler(dataAdded);
dataCollection.ImageRemoved -= new EventHandler(dataRemoved);
dataCollection.ImageIndexChanged -= new EventHandler(dataIndexChanged);
dataCollection.ImageListCleared -= new EventHandler(dataListCleared);
}
internal static void dataAdded(object sender, EventArgs e) {}
internal static void dataRemoved(object sender, EventArgs e) {}
internal static void dataIndexChanged(object sender, EventArgs e) {}
internal static void dataListCleared(object sender, EventArgs e) {}
}
Then override the base event handlers in the subclassed forms?
But, I cannot do this and use the WeifenLuo.WinFormsUI.Docking library...
Well, I could have DataCollectionObserver inherit DockContent from WeifenLuo.WinFormsUI.Docking, but that creates a situation where I need to have two DataCollectionObserver classes -
one which inherits Form and another that inherits DockContent :-[
or, I could make the DataCollectionObserver an Interface, but that still leaves me with duplicate code laying about...
So, does anyone have a suggestion here? Am I missing something obvious, or is this a situation where duplication of code 'must be done' for the sake of simplicity?
Edit://
I am not having problems getting notification in my forms. As a matter of fact, the whole thing is working right now. The reason that I am asking is because the whole thing "smells" due to the block copy and paste of code in these four different forms that I have which subscribe to the collection events and unsubscribe on Form.Closing().
What I would like to do is implement the behavior that I have copied and pasted to these four forms in one place and have the forms that should receive collection change notifications implement that behavior as needed.
Hope that makes things clearer?
FWIW, this is my collection class:
using System;
using System.Collections;
using System.Reflection;
namespace MyNameSpace.Collections
{
/// <summary>
/// Generic Collection of Objects with Events
/// </summary>
public class CollectionWithEvents<T> : CollectionBase
{
public bool SuppressEventNotification
{
get;
set;
}
public CollectionWithEvents()
{
SuppressEventNotification = false;
}
#region Events
/// <summary>
/// Raises before an item is added to the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> BeforeItemAdded;
/// <summary>
/// Raises when an item is added to the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> ItemAdded;
/// <summary>
/// Raises before a collection of items is added to the list.
/// </summary>
public event EventHandler<ItemsEventArgs<T>> BeforeItemsAdded;
/// <summary>
/// Raises when a collection of items is added to the list.
/// </summary>
public event EventHandler<ItemsEventArgs<T>> ItemsAdded;
/// <summary>
/// Raises before an item is changed in the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> BeforeItemChanged;
/// <summary>
/// Raises when an item is changed in the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> ItemChanged;
/// <summary>
/// Raises before an item is removed from the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> BeforeItemRemoved;
/// <summary>
/// Raises when an item is removed from the list.
/// </summary>
public event EventHandler<ItemEventArgs<T>> ItemRemoved;
/// <summary>
/// Raises when the items are cleared from the list.
/// </summary>
public event EventHandler<EventArgs> ItemsCleared;
#endregion
public T this[int index]
{
get { return (T)this.List[index]; }
set
{
if (!SuppressEventNotification)
{
OnBeforeItemChanged(this, new ItemEventArgs<T>(value));
}
this.List[index] = value;
if (!SuppressEventNotification)
{
OnItemChanged(this, new ItemEventArgs<T>(value));
}
}
}
public int Add(T item)
{
if (!SuppressEventNotification)
{
OnBeforeItemAdded(this, new ItemEventArgs<T>(item));
}
int retValue = this.List.Add(item);
if (!SuppressEventNotification)
{
OnItemAdded(this, new ItemEventArgs<T>(item));
}
return retValue;
}
public void AddRange(Collection<T> collection)
{
T[] tmp = new T[collection.Count];
collection.CopyTo(tmp, 0);
AddRange(tmp);
}
public void AddRange(T[] collection)
{
if (!SuppressEventNotification)
{
OnBeforeItemsAdded(this, new ItemsEventArgs<T>(collection));
}
this.AddRange(collection);
if (!SuppressEventNotification)
{
OnItemsAdded(this, new ItemsEventArgs<T>(collection));
}
}
public bool Contains(T item)
{
return this.List.Contains(item);
}
public void CopyTo(Array array, int index)
{
this.List.CopyTo(array, index);
}
public int IndexOf(T item)
{
return this.List.IndexOf(item);
}
public void Insert(int index, T item)
{
this.List.Insert(index, item);
}
public void Remove(T item)
{
if (!SuppressEventNotification)
{
OnBeforeItemRemoved(this, new ItemEventArgs<T>(item));
}
T tmp = (T)item;
this.List.Remove(item);
if (!SuppressEventNotification)
{
OnItemRemoved(this, new ItemEventArgs<T>(tmp));
}
tmp = default(T);
}
public void Sort(string Property, Common.SortOrder Order)
{
Common.GenericComparer genericComparer = new Common.GenericComparer(Property, Order);
this.InnerList.Sort(genericComparer);
}
#region Event Methods
/// <summary>
/// Raised before an Item is added to the list.
/// </summary>
/// <param name="sender">object</param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnBeforeItemAdded(object sender, ItemEventArgs<T> e)
{
if (BeforeItemAdded != null)
{
BeforeItemAdded(sender, e);
}
}
/// <summary>
/// Raised when an Item is added to the list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnItemAdded(object sender, ItemEventArgs<T> e)
{
if (ItemAdded != null)
{
ItemAdded(sender, e);
}
}
/// <summary>
/// Raised before a collection of Items is added to the list.
/// </summary>
/// <param name="sender">object</param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnBeforeItemsAdded(object sender, ItemsEventArgs<T> e)
{
if (BeforeItemsAdded != null)
{
BeforeItemsAdded(sender, e);
}
}
/// <summary>
/// Raised when a collection of Items is added to the list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnItemsAdded(object sender, ItemsEventArgs<T> e)
{
if (ItemsAdded != null)
{
ItemsAdded(sender, e);
}
}
/// <summary>
/// Raised before an Item is changed to the list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">GenericItemEventArgs</param>
protected virtual void OnBeforeItemChanged(object sender, ItemEventArgs<T> e)
{
if (BeforeItemChanged != null)
{
BeforeItemChanged(sender, e);
}
}
/// <summary>
/// Raised when an Item is changed to the list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnItemChanged(object sender, ItemEventArgs<T> e)
{
if (ItemChanged != null)
{
ItemChanged(sender, e);
}
}
/// <summary>
/// Raised before an Item is removed from the list.
/// </summary>
/// <param name="sender"></param>
/// <param name="e">ItemEventArgs</param>
protected virtual void OnBeforeItemRemoved(object sender, ItemEventArgs<T> e)
{
if (BeforeItemRemoved != null)
{
BeforeItemRemoved(sender, e);
}
}
/// <summary>
/// Raised when an Item is removed from the list.
/// </summary>
/// <param name="sender">object</param>
/// <param name="e">ItemEventsArgs</param>
protected virtual void OnItemRemoved(object sender, ItemEventArgs<T> e)
{
if (ItemRemoved != null)
{
ItemRemoved(sender, e);
}
}
/// <summary>
/// Raised when the Items are cleared from this list.
/// </summary>
/// <param name="sender">object</param>
/// <param name="e">EventArgs</param>
protected virtual void OnItemsCleared(object sender, EventArgs e)
{
if (ItemsCleared != null)
{
ItemsCleared(sender, e);
}
}
#endregion
}
public class ItemEventArgs<T> : EventArgs
{
/// <summary>
/// Item
/// </summary>
public T Item { get; private set; }
/// <summary>
/// Default constructor
/// </summary>
/// <param name="Item"></param>
public ItemEventArgs(T Item)
{
this.Item = Item;
}
}
public class ItemsEventArgs<T> : EventArgs
{
/// <summary>
/// Items
/// </summary>
public T[] Items { get; private set; }
/// <summary>
/// Default constructor
/// </summary>
/// <param name="Items"></param>
public ItemsEventArgs(T[] Items)
{
this.Items = Items;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我可能错了。但你可以这样做,你的继承问题就不会出现。我将尝试给出一个简单的示例:
您的集合类可以是这种类型:
具有两个自定义事件处理程序的非常简单的类:
这里没有什么难以理解的,然后基于三种形式,您可以通过这种方式使用您的表单。
第一个包含两个按钮来与集合交互,并创建两个表单来观察您的集合:
集合链接到将在此处观察到的表单的每个功能:
因此我们需要实现这些表单:
I我从 Form 继承了我的东西,但它可以从您实际上想要的任何东西继承。如果您想在不同形式之间共享一些代码,请考虑静态类中的辅助函数,或者可能适合您需要的任何模式。
希望它能有所帮助,并且我并没有完全超出范围!
[编辑] 哎呀没有看到编辑,对不起朋友![/编辑]
I might be mistaken. But you could do it this way and your inheritance problem would not be present. I'll try to give a simple example :
You collection class could be of this kind :
Really simple class with two customized EventHandlers :
Nothing hard to understand here and then based on the three forms you could use your forms this way.
The first one holds two buttons to interact with the collection and creates the two forms which will observe your collection :
The collection gets linked to each of the functions of the forms that will be observed here :
And so we need to implement those forms :
I am inheriting my stuff from Form but it could be inherited form whatever you want actually. If you want to share some code among different forms, think of helper functions in a static class, or of whatever pattern that might suit your need.
Hope it helps a bit, and that I am not completely out of scope!
[EDIT] Oops didn't see the Edit, sorry pal![/EDIT]
您正在使用哪个版本的.net,如果它 >= 3.5 ,您可以利用 ObservableCollection 来实现您正在做的事情
Which version of .net ,you are using if it is >= 3.5 , you can make use of ObservableCollection to achive what ever you are doing
框架中有一个“ObservableCollection”专门用于此类事情。请参阅此处。
There is an 'ObservableCollection' in the Framework just for this type of thing. See here.