2

(before anyone asks, the title is right: I have code working only at design time in Blend, while the most common by far would be the opposite :o )

While designing a DataTemplate in Expression Blend, I can see my DataTriggers working fine, my sample ViewModel generates a random value for the level of a battery, and both border width and background color display accordingly, either in the BatteryLevelTemplate itself, and another panel containing a lot of devices with their respective (random) battery level, with a design-time DataContext.

Here is a screenshot from Expression Blend:

enter image description here

And here a screenshot from the running application. Notice that, while both use exactely the same class as DataContext (but as design time in Blend), at runtime only the default RedBattery color setter is applied, even if the value itself (which also affects width) varies:

enter image description here

And here are the relevant code parts:

                    <Border.Width>
                        <MultiBinding Converter="{StaticResource NormalValueConverter}" FallbackValue="10">
                            <Binding Path="NívelBateria"/>
                            <Binding Path="ActualWidth" ElementName="BatteryChargeContainer"/>
                        </MultiBinding>
                    </Border.Width>
                    <Border.Style>
                        <Style TargetType="Border">
                            <Setter Property="Background">
                                <Setter.Value>
                                    <SolidColorBrush Color="{StaticResource BatteryRed}"/>
                                </Setter.Value>
                            </Setter>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding NívelBateria, Converter={StaticResource ValorMaiorQue}, ConverterParameter=0.25}" Value="True">
                                    <Setter Property="Background">
                                        <Setter.Value>
                                            <SolidColorBrush Color="{StaticResource BatteryOrange}"/>
                                        </Setter.Value>
                                    </Setter>                                       
                                </DataTrigger>
                                <DataTrigger Binding="{Binding NívelBateria, Converter={StaticResource ValorMaiorQue}, ConverterParameter=0.5}" Value="True">
                                    <Setter Property="Background">
                                        <Setter.Value>
                                            <SolidColorBrush Color="{StaticResource BatteryYellow}"/>
                                        </Setter.Value>
                                    </Setter>                                       
                                </DataTrigger>
                                <DataTrigger Binding="{Binding NívelBateria, Converter={StaticResource ValorMaiorQue}, ConverterParameter=0.75}" Value="True">
                                    <Setter Property="Background">
                                        <Setter.Value>
                                            <SolidColorBrush Color="{StaticResource BatteryGreen}"/>
                                        </Setter.Value>
                                    </Setter>                                       
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Border.Style>

============

        <DockPanel x:Name="PainelSetupsSensores" Background="#FFB8E6E8"/>
        <DockPanel x:Name="PainelSensoresDisponiveis" Background="#FFF0F0F0"
            Grid.RowSpan="2" Grid.Column="1" 
            DataContext="{Binding ReceiverAtivo}"
            d:DataContext="{d:DesignInstance Type=local:ReceiverSimulado, IsDesignTimeCreatable=True}">
            <ScrollViewer>
                <ItemsControl  ItemsSource="{Binding Sensores}" Margin="10">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <WrapPanel/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </ScrollViewer>
        </DockPanel>

====================

class ValorMaiorQue : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double valor = (double)value;
        double limite = double.Parse((string)parameter);

        return valor > limite;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

UPDATE (using the valuable Snoop tip by Contango):

I "snooped" the BatteryCharge (Border) element, and found out an interesting thing:

  • The Width property, which is affected by a Multi Value Element Binding, is working fine and displays in a "Local", green-shaded row;
  • On the other hand, the Background property, which is not working, displays unsurprisingly as Style with the default red value. This one is not being "DataTriggered".

enter image description here

My doubt now is how I am supposed to use Snoop (or anything else) to find out why the DataTrigger is not being applied.

lokusking
  • 7,396
  • 13
  • 38
  • 57
heltonbiker
  • 26,657
  • 28
  • 137
  • 252

2 Answers2

3

I discovered the problem "accidentally", and here goes the explanation:

  1. I installed Snoop, TriggerTracing and also WPF Inspector to check properties applied by my DataTriggers, and found out the comparison provided by the DataConverter was always False;
  2. Then I put a breakpoing inside the DataConverter, to discover that, for example, the string "0.75" provided by ConverterParameter was being Double.Parsed as 75.0;
  3. Then I realized that my current language is pt-BR, and the decimal separator is comma instead of dot. Then I changed the converter, adding an InvariantCulture parameter to Double.Parse. And now it works!

    double limite = double.Parse((string)parameter, CultureInfo.InvariantCulture);

heltonbiker
  • 26,657
  • 28
  • 137
  • 252
0

Your run time DataContext is not being set correctly, so your code can't bind to the correct properties at runtime.

Note that the run time DataContext is completely separate to the design time DataContext, and uses different XAML to setting the runtime DataContext.

I would recommend using Snoop to fix the problem, you can use it to flag up binding errors due to a bad runtime DataContext, see my answer here:

ReSharper WPF error: "Cannot resolve symbol "MyVariable" due to unknown DataContext"

Community
  • 1
  • 1
Contango
  • 76,540
  • 58
  • 260
  • 305
  • 1
    Bu then, how come every other property is set correctly? The very default red background, set in the default setter from the datafgrid, from the style, from the template, is working. That is, necessarily the datacontext is working, the datatemplate is working, the style is working and the setter is working, only the _data triggers_ apparently are not working... – heltonbiker May 22 '15 at 22:30
  • Good point. Usually, things like this trace back to a bad DataContext somewhere. Could you run Snoop and check to see if all DataContexts are set correctly at runtime? See the final link in my answer. – Contango May 24 '15 at 14:34
  • Unfortunately I don't have ReSharper or Snoop. Tomorrow I plan to do some step-by-step testing to see if I find out where the problem is, thanks. – heltonbiker May 24 '15 at 19:06
  • Snoop is free! Google "wpf snoop" – Contango May 24 '15 at 22:55
  • Yes, Snoop is an amazing tool for WPF, it will auto discover any bad DataBinding at runtime if the filters are switched on, see the referenced URL in my answer. – Contango May 25 '15 at 10:29
  • I installed it, and it's really great and easy to use. Then I drilled down the visual tree until I got to the `BatteryCharge` Border in the first templated item, but everything seems fine, except the `Background` property which is Red, (Value Source = Style). I couldn't find out if the DataTriggers are working or not (I don't know how to do it). – heltonbiker May 25 '15 at 12:43