Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to remove a Trigger

Tags:

c#

wpf

I am working with a form where some ComboBoxes can be created and removed programmatically.

When they are created, some triggers which target them are created and applied to a button:

    Dictionary<ComboBox, DataTrigger> triggers = new Dictionary<ComboBox, DataTrigger>();

    private void CreateTrigger(ComboBox box)
    {
        Style s = new Style(typeof(Button), MyButton.Style);
        foreach(TriggerBase aTrigger in MyButton.Style.Triggers)
            s.Triggers.Add(aTrigger);

        DataTrigger t = new DataTrigger 
          { 
            Binding = new Binding("SelectedItem") { Source = box }, 
            Value = null 
          };
        t.Setters.Add(new Setter(Button.IsEnabledProperty, false));
        s.Triggers.Add(t);

        triggers.Add(box, t);

        MyButton.Style = s;
    }

So far so good*. . . the problem is, what to do when the ComboBox is removed from the window. I need to remove the trigger from the button's Style, since I no longer want the ComboBox to influence its behavior. I tried the most obvious option:

    private void RemoveTrigger(ComboBox box)
    {
        Style s = new Style(typeof(Button), MyButton.Style);
        foreach(TriggerBase aTrigger in MyButton.Style)
            if(aTrigger != triggers[box]) s.Triggers.Add(aTrigger);

        triggers.Remove(box);

        MyButton.Style = s;
    }

But this does not seem to do the job - if the trigger is removed while it is active, then the button stays disabled.

I had assumed that the button would re-evaluate its Style whenever it is given a new one. that seems to be happening when the trigger is added, but not when it's being removed - what am I missing here?

EDIT: Changed code for adding/removing triggers as per the advice in H.B.'s comment. However, the problem in question remains.

EDIT 2: *Maybe not so far so good after all - I went on to try adding an additional ComboBox (and trigger) and discovered that adding a second trigger seems to break the first one. Using this code, only the most recently added trigger works. Should I be perhaps thinking of a FrameworkElement's triggers as a write-once collection and finding a different way to achieve this kind of behavior?

like image 986
Sean U Avatar asked Jul 25 '11 20:07

Sean U


2 Answers

So you create a style BasedOn the style of MyButton (that is what this contructor does), then you add the trigger and change the reference of your button's style to your new style. In the removal you create a new style, again based on the style currently referenced by your button, remove a trigger from its trigger collection which will not do anything as the collection is empty and then reassign this style again.

Nope, this of course won't work.

Edit: Create a base-style as a readonly reference, then when those dynamic triggers are to be added or removed create a new style based on your reference and recreate all triggers while iterating over your trigger-collection.

like image 149
H.B. Avatar answered Oct 13 '22 20:10

H.B.


It's been a long time since this question was asked, but I figured I'd at least post how I resolved the issue for the sake of sharing:

I never did find a way to remove triggers that worked reliably. So instead, I added a property to my View which indicated how all the triggers would have evaluated, if they had existed, and hooked a DataTrigger up to this property.

public bool TriggerPoseur { get; set; }  // Actually notifies when it changes

In place of adding and removing triggers, created an handlers to watch the properties that the triggers would have watched:

public void ComboBoxDataContext_SelectedItemChanged(object sender, PropertyChangedEventArgs e) { //update TriggerPoseur }

This sidesteps all the hassle with creating and removing triggers. Instead there's one trigger, and adding and removing event handlers works just fine.

(Hacky, yes.)

like image 36
Sean U Avatar answered Oct 13 '22 20:10

Sean U