如何避免WPF中事件的递归触发? [英] How to avoid recursive triggering of events in WPF?

查看:102
本文介绍了如何避免WPF中事件的递归触发?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个WPF(来自标准集)小部件A和B.当我更改A的某些属性时,应将其设置在B上,当更改B中的属性时,应将其设置在A上.

现在我有一个丑陋的递归->我更改了A,所以代码也更改了B,但是由于B更改了,所以它更改了A,所以它更改了B.

如何以最标准"的方式避免这种递归?天真的删除和添加事件处理程序不起作用,并且检查新值是否与旧值在此处不适用(由于计算的波动-我没有为A和B设置相同的值,而是对其进行了转换)

背景

我总是尽量减少有关该问题的信息,以免造成混淆.但是,这可能有帮助

  • 我没有写那些小部件,我只是处理事件,仅此而已
  • 尽管标题为递归触发",但将依次调用处理程序,因此您具有的顺序为entry-exit-entry-exit-entry-exit,而不是entry-entry-entry-exit-exit-exit

    最后一个,也许是最不重要的,但是

  • 在这种情况下,我有A和B的通用处理程序

A和B(在这种情况下)是滚动查看器,我试图为它们两个按比例地保持相同的位置.该项目(由Karin Huber设计)在这里: http://www.codeproject.com/KB/WPF/ScrollSynchronization.aspx

事件触发

阻止事件的想法非常流行,以至于我添加了触发事件的顺序,下面我们开始:

  • 我更改A
  • 一个处理程序被称为
  • 我禁用了A的处理程序
  • 我更改了B(已存储但未触发)
  • 我启用A的处理程序
  • 现在事件是从队列中获取的
  • B处理程序称为
  • 我禁用了B的处理程序
  • 我换A
  • ...

如您所见,这是徒劳的.

解决方案

首先,我会考虑一下设计,因为这些循环依赖性通常是不良设计的标志.

但是,在某些情况下,这种依赖关系是唯一的解决方法.在这种情况下,我建议使用私有标志来指示B的更改是否由A的更改引起.诸如此类(已更新):

 公共类A{私人布尔m_ignoreChangesInB = false;私有void B_ChangeOccurred(对象发送者,EventArgs e){如果(!m_ignoreChangesInB){//处理更改...}}私人无效SomeMethodThatChangesB(){m_ignoreChangesInB = true;//在B中执行更改...m_ignoreChangesInB = false;}} 

在类B中应使用相同的方法.但是,此方法不能处理来自多个线程的更改.如果可能同时从多个线程更改A或B,则必须使用适当的技术来避免丢失属性更改.

I am having two WPF (from the standard set) widgets A and B. When I change some property of A it should be set on B, when it is change in B it should be set on A.

Now I have this ugly recursion --> I change A, so code changes B, but since B is changed, it changes A, so it changes B... You have the picture.

How to avoid this recursion the most "standard" way? Naive deleting and adding event handlers does not work, and checking if the new value is the same as old value is not applicable here (because of the fluctuation of calculation -- I am not setting the same value to A and B, but transformed).

Background

I always try to put minimum info about the problem to avoid confusion. However, this might help

  • I didn't write those widgets, I just handle the events, that's all
  • despite the title "recursive triggering", the handlers are called sequentially, so you have the sequence entry-exit-entry-exit-entry-exit, not entry-entry-entry-exit-exit-exit

    and the last, probably the least important, but nevertheless

  • in this particular case I have common handler for A and B

A and B (in this case) are scrollviewers and I try to maintain proportionally the same position for both of them. The project (by Karin Huber) is here: http://www.codeproject.com/KB/WPF/ScrollSynchronization.aspx

Event triggering

The idea of blocking the events is so popular that I added the sequence of triggering the events, here we go:

  • I change the A
  • A handler is called
  • I disable handler of A
  • I change B (this is stored, but not triggered)
  • I enable handler of A
  • now the event is get from the queue
  • B handler is called
  • I disable handler of B
  • I change A
  • ...

As you see, this is futile.

解决方案

First of all, I would think about the design because those circular dependencies are often a sign of bad design.

However, there might be situations where such dependencies are the only way to go. In these case, I would suggest to use private flags indicating whether a change in B was caused by a change in A. Something like this (updated):

public class A
{
    private bool m_ignoreChangesInB = false;

    private void B_ChangeOccurred(object sender, EventArgs e)
    {
        if (!m_ignoreChangesInB)
        {
            // handle the changes...
        }
    }

    private void SomeMethodThatChangesB()
    {
        m_ignoreChangesInB = true;
        // perform changes in B...
        m_ignoreChangesInB = false;
    }
}

The same approach should be used in class B. However, this approach does not handle changes from multiple threads. If A or B might be changed from multiple threads at the same time, you will have to use appropriate techniques to avoid that property changes are lost.

这篇关于如何避免WPF中事件的递归触发?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆