WPF triggers affecting values set in code, not XAML
Question
In my app I have toggle buttons that have three possible states; "Unchecked", "Checked", and "Previously Used". When the user comes to this particular screen, some of the toggle buttons will be in the "Previously Used" state to show what work has been done. Clicking on a toggle button (no matter the current state) will place it into the "Checked" state. Only one of these toggle buttons can be checked at a time. The different states are indicated by different colored outer glow, or no glow at all.
To set the outer glow for the "Checked" state I use a trigger on IsChecked euqals true.
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="Salmon" BlurRadius="40" ShadowDepth="0" Opacity="1.0"></DropShadowEffect>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
For the "Previously Used" state I apply the outer glow in code, not markup. I have to do this because determining if the button should be in this state is done by checking values in a List.
if (mExistingViews.Contains(mViews[i].LocalizedName))
{
DropShadowEffect dse = new DropShadowEffect();
dse.ShadowDepth = 0;
dse.BlurRadius = 20;
dse.Opacity = 1.0;
dse.Color = Colors.Yellow;
mViewButtons[i].Effect = dse;
}
However, when a toggle button is clicked when in the "Previously Used" state, the trigger doesn't seem to have any effect. The outer glow does not change.
What am I doing wrong? Will a trigger not effect something that has not been set in XAML?
Solution
Once you set the DropShadowEffect
on the Button
, you are setting the local value of the Button
's Effect
property, which is a DependencyProperty
(Button.EffectProperty
). The local value overrides any other possible value until it is cleared like this:
button1.ClearValue( Button.EffectProperty );
However, that just makes the workings a bit more convoluted, because you also have to make sure you clear it if was set before and hasn't been cleared yet.
Instead, you could create an AttachedProperty PreviouslyUsed
to put on the ToggleButton
s and use Bindings
so they get their value a bit more automagically. Then refer to this AttachedProperty value in your triggers and you'll have one drop shadow for PreviouslyUsed
, and another for IsChecked
.
The part you'll have to wire up is the binding, and you'll probably have to use an IValueConverter
somewhere to turn mViews[i].LocalizedName
into a true
or false
for PreviouslyUsed
.
Unfortunately, I don't know enough about your setup with mViews
and such to offer more advice about that. I don't know whether your ToggleButtons
are part of databinding or not. I suspect that they are not, as you seem to be iterating an array of them. If you bound your mViews
objects to the ItemsSource
of a ListBox
, for example, you could create a DataTemplate
that generates the ToggleButtons
with the AttachedProperty already in place. That would also simplify your IsChecked
situation by binding it to whether or not that item is selected in the ListBox
, and then the ListBox
takes care of making sure that only one is selected.