Edward J Brown
Edward J Brown

Reputation: 331

WPF DataTrigger not setting when bound value changed

I have a data template which defines a line to display for every NodePairViewModel drawn inside by a canvas ItemsPanel. The line colour should change when the IsChecked Property of the NodePairViewModel being represented changes as defined in the style (see below) however when this property is set the colour does not change. INotifyPropertyChanged is implemented and I have verified that this event is firing. I cannot see anything obviously wrong and the same setup works for NodeViewModels which are also drawn in the same itemspanel.

    <DataTemplate DataType="{x:Type vm:NodePairViewModel}">
        <Line Canvas.ZIndex="2" Name="Arc" Stroke="Blue" StrokeThickness="3" 
              X1="{Binding Path=NodeA.PositionX, Mode=OneWay, Converter={StaticResource NodeLinkXConverter}}" 
              X2="{Binding Path=NodeB.PositionX, Mode=OneWay, Converter={StaticResource NodeLinkXConverter}}" 
              Y1="{Binding Path=NodeA.PositionY, Mode=OneWay, Converter={StaticResource NodeLinkYConverter}}" 
              Y2="{Binding Path=NodeB.PositionY, Mode=OneWay, Converter={StaticResource NodeLinkYConverter}}" 
              MouseLeftButtonDown="Arc_MouseLeftButtonDown" MouseLeftButtonUp="Arc_MouseLeftButtonUp">
            <Line.Style>
                <Style TargetType="Line">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=IsChecked}" Value="True">
                            <Setter Property="Stroke" Value="Orange"></Setter>
                            </DataTrigger>

<DataTrigger Binding="{Binding Path=IsSelected, Mode=OneWay}" Value="True">
                                <Setter Property="Stroke" Value="Red"/>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding Path=IsRejected, Mode=OneWay}" Value="True">
                                <Setter Property="Stroke" Value="LightGray"/>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding Path=IsVisited}" Value="True">
                                <Setter Property="Stroke" Value="LightGreen"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Line.Style>
            </Line>
        </DataTemplate>


<ItemsControl Name="NodeSpace" ItemsSource="{Binding GraphItems}" Margin="5" MouseMove="NodeSpace_MouseMove" MouseDown="NodeSpace_MouseDown" MouseLeftButtonUp="NodeSpace_MouseLeftButtonUp" MouseLeftButtonDown="NodeSpace_MouseLeftButtonDown" MouseRightButtonDown="NodeSpace_MouseRightButtonDown" RenderTransformOrigin="0.5,0.5" Grid.Column="1" Grid.Row="1">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Canvas Name="GraphSurface" Background="#FFFFFE"></Canvas>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemContainerStyle>
                        <Style TargetType="ContentPresenter">
                            <Setter Property="Canvas.Left">
                                <Setter.Value>
                                    <Binding Mode="OneWay" Path="PositionX" Converter="{StaticResource XInverseConverter}"/>
                                </Setter.Value>
                            </Setter>
                            <Setter Property="Canvas.Top">
                                <Setter.Value>
                                    <Binding Mode="OneWay" Path="PositionY" Converter="{StaticResource YInverseConverter}"/>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ItemsControl.ItemContainerStyle>
                </ItemsControl>

And the IsChecked property itself

private bool ArcIsChecked = false;
public bool IsChecked 
{
    get
    {
        return ArcIsChecked;
    }
    set
    {
        ArcIsChecked = value;
        RaisePropertyChanged("IsChecked");
    }
}

Upvotes: 1

Views: 1111

Answers (1)

dkozl
dkozl

Reputation: 33364

You need to move default value from Line

<Line ... Stroke="Blue">

into Style as Setter

<Line 
   Canvas.ZIndex="2" 
   Name="Arc" 
   StrokeThickness="3" 
   X1="{Binding Path=NodeA.PositionX, Mode=OneWay, Converter={StaticResource NodeLinkXConverter}}" 
   X2="{Binding Path=NodeB.PositionX, Mode=OneWay, Converter={StaticResource NodeLinkXConverter}}" 
   Y1="{Binding Path=NodeA.PositionY, Mode=OneWay, Converter={StaticResource NodeLinkYConverter}}" 
   Y2="{Binding Path=NodeB.PositionY, Mode=OneWay, Converter={StaticResource NodeLinkYConverter}}" 
   MouseLeftButtonDown="Arc_MouseLeftButtonDown" 
   MouseLeftButtonUp="Arc_MouseLeftButtonUp">
   <Line.Style>
      <Style TargetType="{x:Type Line}">
         <Setter Property="Stroke" Value="Blue"/>
         <Style.Triggers>
            <DataTrigger Binding="{Binding Path=IsChecked}" Value="True">
               <Setter Property="Stroke" Value="Orange"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=IsSelected, Mode=OneWay}" Value="True">
               <Setter Property="Stroke" Value="Red"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=IsRejected, Mode=OneWay}" Value="True">
               <Setter Property="Stroke" Value="LightGray"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=IsVisited}" Value="True">
               <Setter Property="Stroke" Value="LightGreen"/>
            </DataTrigger>
         </Style.Triggers>
      </Style>
   </Line.Style>
</Line>

according to Dependency Property Setting Precedence List style trigger is lower in hierarchy then local value so it won't be able to overwrite your default (local) value

Upvotes: 4

Related Questions