C# 如何处理顺序调用事件处理程序?

C# 如何处理顺序调用事件处理程序?,c#,events,C#,Events,在我重新发明轮子之前 这只是一个用于描述问题的示例-- 在后端,我有ItemIndex——每当它发生更改时,就会触发OnScroll事件 我还有AddNewItem方法,它在集合的末尾添加新项。方法的结尾是调用OnNewItem事件处理程序 这里是一个陷阱——在AddNewItem中,我必须更改ItemIndex,它在Croll上激发。显示所选项目的(!)OnScroll和OnNewItem if前端接收器之一 在这种情况下,它被称为两次(不好)。一种解决方案是改变item_索引而不是ItemI

在我重新发明轮子之前

这只是一个用于描述问题的示例--

在后端,我有ItemIndex——每当它发生更改时,就会触发OnScroll事件

我还有AddNewItem方法,它在集合的末尾添加新项。方法的结尾是调用OnNewItem事件处理程序

这里是一个陷阱——在AddNewItem中,我必须更改ItemIndex,它在Croll上激发。显示所选项目的(!)OnScroll和OnNewItem if前端接收器之一

在这种情况下,它被称为两次(不好)。一种解决方案是改变item_索引而不是ItemIndex,这样可以防止OnScroll,但我不喜欢它,因为ItemIndex不再充当黑盒

是否有任何既定的顺序触发事件模式,并且只发送“重要”事件(此处:OnNewItem覆盖OnScroll)?我的想法是定义一个事件作用域,然后不直接发送事件,只需注册它们以便发送,在作用域结束时对它们进行排序并发送所需的事件


一般来说--问题--我应该如何处理潜在的顺序事件触发。是否使用内部构件来避免发送冗余事件?忽略开销

您可以将两个事件指向一个函数。该函数可以确定发送者并执行适当的操作。

您可以将两个事件指向一个函数。该函数可以确定发送者并执行适当的操作。

答案对我来说似乎很明显,尽管我可能很容易错过一些东西:

private bool IsAdding { get; set; }
private int item_index;
private IList m_collection;

public void AddNewItem(object item)
{
    if (item == null)
    {
        throw new Exception("Cannot add null item."); // little bit of contracting never hurts
    }

    m_collection.Add(item);
    IsAdding = true;
    ItemIndex = collection.Count - 1; //I'm just making assumptions about this piece but it is not important how you decide what your index is to answer the question

    if (OnNewItem != null)
    {
       OnNewItem(this, EventArgs.Empty); 
    }
}

public int ItemIndex
{
   get { return item_index =; }
   set
   {
       item_index = value;
       if (!IsAdding && OnScroll != null) //won't double fire event thanks to IsAdding
       {
           OnScroll(this, EventArgs.Empty);
       }
       IsAdding = false; //need to reset it
   }
}
我要注意的一点是,您提到只需直接修改item_索引,但这不会有黑盒行为。好吧,黑匣子很好。。。但是这个术语只适用于与我们已经讨论过的类交互的对象


您应该感到有权在类内部使用它。将黑盒项放在其自身内是不好的OOP。如果您正在这样做,那么您的类可能存在设计问题,应该将其分为多个类。

答案对我来说似乎很明显,尽管我可能很容易错过一些东西:

private bool IsAdding { get; set; }
private int item_index;
private IList m_collection;

public void AddNewItem(object item)
{
    if (item == null)
    {
        throw new Exception("Cannot add null item."); // little bit of contracting never hurts
    }

    m_collection.Add(item);
    IsAdding = true;
    ItemIndex = collection.Count - 1; //I'm just making assumptions about this piece but it is not important how you decide what your index is to answer the question

    if (OnNewItem != null)
    {
       OnNewItem(this, EventArgs.Empty); 
    }
}

public int ItemIndex
{
   get { return item_index =; }
   set
   {
       item_index = value;
       if (!IsAdding && OnScroll != null) //won't double fire event thanks to IsAdding
       {
           OnScroll(this, EventArgs.Empty);
       }
       IsAdding = false; //need to reset it
   }
}
我要注意的一点是,您提到只需直接修改item_索引,但这不会有黑盒行为。好吧,黑匣子很好。。。但是这个术语只适用于与我们已经讨论过的类交互的对象


您应该感到有权在类内部使用它。将黑盒项放在其自身内是不好的OOP。如果您正在这样做,那么您的类可能存在设计问题,应该将其拆分为多个类。

一个解决方案是使用某种形式的“闩锁”。更新时,您通过一个助手执行UI操作,该助手设置一个标志,表示“嘿,我处于特殊状态!”。然后,在引发事件时,检查闩锁是否已设置——如果已设置闩锁,则跳过引发这些事件

这基本上是马修所发布内容的一个非常简单、概括的版本。根据情况,设置一个标志可能就足够了


一种解决方案是使用某种形式的“闩锁”。更新时,您通过一个助手执行UI操作,该助手设置一个标志,表示“嘿,我处于特殊状态!”。然后,在引发事件时,检查闩锁是否已设置——如果已设置闩锁,则跳过引发这些事件

这基本上是马修所发布内容的一个非常简单、概括的版本。根据情况,设置一个标志可能就足够了


我喜欢这个问题。我自己也很好奇。我的解决方案总是直接设置字段,或者使用一些不会触发事件的ItemInExinInternal。我的也是,但是如果我的程序变大,这种方法就会有问题。就像那个问题一样。我自己也很好奇。我的解决方案总是直接设置字段,或者使用一些不会触发事件的ItemIndexInternal。我的也是,但如果我的程序变大,这种方法会有问题。只需像平常一样为代理分配一个函数。对不起,我不明白你在说什么。我的代码是ItemIndex=Items.Count-1;如果(OnNewItem!=null)OnNewItem();在哪里可以看到另一个委托的位置?我建议将IndexChanged(或调用事件的任何内容)和AddNewItem事件绑定到同一个函数。然后您可以查看发送者并确定要执行的操作。@Jordan,我不知道这怎么可能。如果我只想更改索引(因为我刚移动到另一个项目,没有添加任何内容),该怎么办?您应该知道哪个事件是触发器。这样你就知道什么时候你应该添加newitem而不是其他任务。就像你通常做的那样,给代理分配一个函数。对不起,我不明白你在说什么。我的代码是ItemIndex=Items.Count-1;如果(OnNewItem!=null)OnNewItem();在哪里可以看到另一个委托的位置?我建议将IndexChanged(或调用事件的任何内容)和AddNewItem事件绑定到同一个函数。然后您可以查看发送者并确定要执行的操作。@Jordan,我不知道这怎么可能。如果我只想更改索引(因为我刚移动到另一个项目,没有添加任何内容),该怎么办?您应该知道哪个事件是触发器。这样你就知道什么时候应该添加NewItem而不是其他任务了。设计的优点是,尽管如此,我还是更喜欢黑匣子——加载、保存、添加、删除等等,很容易错过一些东西。最好花时间在更坚实的设计上,而不是搜索bug,因为每种方法都假定了其他方法的某些方面。我将在添加时使用您的想法,但将其更改为EventPending