[英]Why CellClick event does not fire when SelectionChanged event in DataGridView?
[英]Why WeakEventManager does not fire an event when the sender is not the nominal?
我不喜歡不合標准的模式,但我正在對我的應用程序進行快速測試,並且我遇到了這種奇怪的行為。
考慮一個暴露事件的普通類,這里是非常常見的PropertyChanged,但我認為可能是其他任何一個。
訂戶選擇通過WeakEventManager幫助程序訂閱事件。 現在,“奇怪”的東西是實際的發送者引用:只要實例與訂閱上使用的實例相同,一切都很順利。 但是,當您使用其他對象時,不會發出通知。
同樣,這不是一個好的模式,但我想知道這個限制是否有任何好的理由,或者說這是一種錯誤。 更多的是好奇心而不是真正的需求。
class Class1
{
static void Main(string[] args)
{
var c = new MyClass();
WeakEventManager<INotifyPropertyChanged, PropertyChangedEventArgs>.AddHandler(
c,
"PropertyChanged",
Handler
);
c.ActualSender = c;
c.Number = 123; //will raise
c.ActualSender = new Class1();
c.Number = 456; //won't raise
Console.ReadKey();
}
static void Handler(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine("Handled!");
}
}
class MyClass : INotifyPropertyChanged
{
public object ActualSender { get; set; }
private int _number;
public int Number
{
get { return this._number; }
set
{
if (this._number != value)
{
this._number = value;
this.OnPropertyChanged("Number");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(
string name
)
{
this.PropertyChanged(
this.ActualSender,
new PropertyChangedEventArgs(name)
);
}
}
編輯:這是一種實現預期行為的粗略方法(為簡單起見,硬鏈接)。
class Class1
{
static void Main(string[] args)
{
var cx = new MyClass();
var cy = new MyClass();
Manager.AddHandler(cx, Handler1);
Manager.AddHandler(cx, Handler2);
Manager.AddHandler(cy, Handler1);
Manager.AddHandler(cy, Handler2);
cx.ActualSender = cx;
cx.Number = 123;
cx.ActualSender = new Class1();
cx.Number = 456;
cy.ActualSender = cy;
cy.Number = 789;
cy.ActualSender = new Class1();
cy.Number = 555;
Console.ReadKey();
}
static void Handler1(object sender, PropertyChangedEventArgs e)
{
var sb = new StringBuilder();
sb.AppendFormat("Handled1: {0}", sender);
var c = sender as MyClass;
if (c != null) sb.AppendFormat("; N={0}", c.Number);
Console.WriteLine(sb.ToString());
}
static void Handler2(object sender, PropertyChangedEventArgs e)
{
var sb = new StringBuilder();
sb.AppendFormat("Handled2: {0}", sender);
var c = sender as MyClass;
if (c != null) sb.AppendFormat("; N={0}", c.Number);
Console.WriteLine(sb.ToString());
}
}
static class Manager
{
private static Dictionary<object, Proxy> _table = new Dictionary<object, Proxy>();
public static void AddHandler(
INotifyPropertyChanged source,
PropertyChangedEventHandler handler
)
{
var p = new Proxy();
p._publicHandler = handler;
source.PropertyChanged += p.InternalHandler;
_table[source] = p;
}
class Proxy
{
public PropertyChangedEventHandler _publicHandler;
public void InternalHandler(object sender, PropertyChangedEventArgs args)
{
this._publicHandler(sender, args);
}
}
}
我沒有找到任何有關此內容的文檔,但您可以查看WeakEventManager源代碼以了解發生這種情況的原因。
管理器保持一個表,將已注冊的源對象映射到其處理程序。 請注意,此源對象是您在添加處理程序時傳遞的對象。
當管理器收到事件時,它會使用事件的發送者作為密鑰從該表中查找相關的處理程序。 顯然,如果此發件人與注冊的發件人不同,則找不到預期的處理程序。
編輯
下面是一些偽代碼來說明。
public class PseudoEventManager : IWeakEventListener
{
private static PseudoEventManager _instance = new PseudoEventManager();
private readonly Dictionary<object, List<object>> _handlerTable
= new Dictionary<object, List<object>>();
public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
foreach (var handler in _handlerTable[sender]) // point of interest A
//invoke handler
}
public static void AddHandler(object source, object handler)
{
if (!_instance._handlerTable.ContainsKey(source))
_instance._handlerTable.Add(source, new List<object>()); //point of interest B
_instance._handlerTable[source].Add(handler);
//attach to event
}
}
添加處理程序時,傳入的源將添加到查找表中。 收到事件后,將為此事件的發件人查詢此表,以獲取此發件人/來源的相關處理程序。
在您的示例中,您正在偵聽的源是c
,這是第一次也是ActualSender
的值。 因此,事件的發送者與注冊的源相同,這意味着正確地找到並調用了處理程序。
但是,第二次, ActualSender
是一個與c
不同的實例。 注冊的源不會更改,但sender
參數的值現在不同了! 因此,它將無法檢索處理程序,也無法調用任何內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.