Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid recursive triggering of events in WPF?

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.

like image 702
greenoldman Avatar asked Aug 26 '10 11:08

greenoldman


1 Answers

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.

like image 152
gehho Avatar answered Sep 30 '22 08:09

gehho