2011-10-11 14 views
6

Tengo un disparador de datos WPF que se activa cuando un valor es verdadero.WPF DataTrigger no se activa si el valor sigue siendo el mismo

Quiero disparar este disparador cada vez que este valor se establece en verdadero, incluso si era cierto antes. Desafortunadamente, parece disparar solo si el valor cambia de verdadero a falso o viceversa. Mi modelo de datos subyacente está activando el evento PropertyChanged de INotifyPropertyChanged incluso si el valor se establece en verdadero dos veces seguidas, pero el desencadenador no parece recoger esto.

¿Hay alguna forma de hacer que el disparador se ejecute independientemente de si el valor encuadernado ha cambiado?

Algunos de ustedes han pedido el código, así que aquí está. Es interesante notar que los conversores serán llamados cada vez. El problema es más específico para ejecutar una animación.

Actualización Si cambio mi código para restablecer el valor a falso y luego de nuevo a verdadero, desencadena la animación. Obviamente, esto no es ideal y no hace que el código sea agradable de leer. Espero que haya una mejor manera de hacer esto.

Cualquier ayuda muy apreciada.

código WPF

<Grid> 
    <Grid.Resources>    
     <Storyboard x:Key="AnimateCellBlue"> 
      <ColorAnimation Storyboard.TargetProperty="Background.Color" From="Transparent" To="Blue" Duration="0:0:0.1" AutoReverse="True" RepeatBehavior="1x" /> 
     </Storyboard> 
    </Grid.Resources> 
    <TextBox Name="txtBox" Text="{Binding DataContext.DisplayText, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">   
     <TextBox.Style> 
      <Style TargetType="TextBox"> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding DataContext.IsTrue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Value="True"> 
         <DataTrigger.EnterActions>               
          <BeginStoryboard Name="BidSizeUpStoryB" Storyboard="{StaticResource AnimateCellBlue}" /> 
         </DataTrigger.EnterActions> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </TextBox.Style> 
    </TextBox> 
</Grid> 

código subyacente: -

public partial class MainWindow : Window 
{ 
    private DataItem _dataItem; 
    private DispatcherTimer _dispatcherTimer; 

    public MainWindow() 
    { 
     InitializeComponent(); 

     _dataItem = new DataItem(); 
     _dataItem.DisplayText = "Testing"; 
     _dataItem.IsTrue = true; 

     this.DataContext = _dataItem; 

     _dispatcherTimer = new DispatcherTimer(TimeSpan.FromSeconds(1), DispatcherPriority.Normal, TimerCallbackHandler, Dispatcher); 

    } 

    private void TimerCallbackHandler(object s, EventArgs args) 
    { 
     Console.WriteLine("In Timer"); 
     _dataItem.IsTrue = true; 
     _dataItem.DisplayText = "Timer " + DateTime.Now.Ticks; 
    } 
} 

DataItem: -

public class DataItem : INotifyPropertyChanged 
{ 
    private bool _isTrue; 
    private string _displayText; 

    public bool IsTrue 
    { 
     get { return _isTrue; } 
     set 
     { 
      _isTrue = value; 
      NotifyPropertyChanged("IsTrue"); 
     } 
    } 

    public string DisplayText 
    { 
     get 
     { 
      return _displayText; 
     } 
     set 
     { 
      _displayText = value; 
      NotifyPropertyChanged("DisplayText"); 
     } 
    } 

    #region INotifyPropertyChanged Members 

    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion 

    private void NotifyPropertyChanged(string info) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(info)); 
    } 
} 
+1

Muéstranos el código de la propiedad y el activador para que no tengamos que adivinar. –

+0

Por favor vea mi código de muestra arriba. La animación se disparará solo una vez. – user630190

Respuesta

1

El disparador será fuego, independientemente del valor establecido. Cada vez que se genera un evento PropertyChanged para la propiedad enlazada con trigger, se llamará al desencadenador. Aquí está la muestra en la que he verificado -

<TextBox> 
    <TextBox.Style> 
     <Style TargetType="TextBox"> 
      <Style.Triggers> 
      <DataTrigger Binding="{Binding DataContext.IsTrue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, 
                 Converter={StaticResource MyConverter}}" Value="True"> 
        <Setter Property="Background" Value="Red"/> 
      </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </TextBox.Style> 
</TextBox> 

pongo el punto de interrupción en mi convertidor y se llamaron cada vez que levanto caso PropertyChanged de la propiedad es verdadera. Debe haber algún otro problema en su código. ¿Puedes mostrar un poco de tu código donde te enfrentas a este problema?

+0

Por favor, vea mi pregunta ammended con muestra de código. Es la animación que no está disparando – user630190

0

Actualización: parece que mi primera respuesta dependió de mis ValueConverters. Por lo tanto, investigué un poco más y descubrí ConditionalBehavior y PropertyChangedTrigger

Aquí hay uno que probé.

<UserControl 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
      xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
      x:Class="WpfControlLibrary1.UserControl1" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <UserControl.Triggers> 
     <EventTrigger RoutedEvent="FrameworkElement.Loaded"/> 
    </UserControl.Triggers> 
    <Grid> 
     <i:Interaction.Triggers> 
      <!--Use multiple PropertyChangedTriggers to handle multiple conditions--> 
      <!--True State--> 
      <ei:PropertyChangedTrigger Binding="{Binding DataContext.IsTrue, 
        RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}" > 
       <i:Interaction.Behaviors> 
        <!--This is just a humble demonstration of Conditional Behavior, it's has so much potential that you can replicate complex if conditions--> 
        <ei:ConditionBehavior> 
         <ei:ConditionalExpression ForwardChaining="And"> 
          <ei:ComparisonCondition Operator="Equal" 
           LeftOperand="{Binding DataContext.IsTrue, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}" 
           RightOperand="True" 
          /> 
         </ei:ConditionalExpression> 
        </ei:ConditionBehavior> 
       </i:Interaction.Behaviors> 
       <!--I'm not sure why, but I needed to apply the default state first so that the true state plays it's storyboard.--> 
       <!--If you don't do this, this behaves like a data trigger.--> 
       <ei:GoToStateAction StateName="DefaultState"/> 
       <ei:GoToStateAction StateName="TrueState"/> 
      </ei:PropertyChangedTrigger> 

      <!--False state--> 
      <ei:PropertyChangedTrigger Binding="{Binding DataContext.IsTrue, 
        RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}" > 
       <i:Interaction.Behaviors> 
        <ei:ConditionBehavior> 
         <ei:ConditionalExpression ForwardChaining="And"> 
          <ei:ComparisonCondition Operator="Equal" 
           LeftOperand="{Binding DataContext.IsTrue, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}" 
           RightOperand="False" 
          /> 
         </ei:ConditionalExpression> 
        </ei:ConditionBehavior> 
       </i:Interaction.Behaviors> 
       <ei:GoToStateAction StateName="DefaultState"/> 
      </ei:PropertyChangedTrigger> 
     </i:Interaction.Triggers> 
     <VisualStateManager.VisualStateGroups> 
      <VisualStateGroup x:Name="VisualStateGroup"> 
       <VisualState x:Name="DefaultState"/> 
       <VisualState x:Name="TrueState"> 
        <Storyboard Storyboard.TargetName="txtBox" > 
         <ColorAnimation Storyboard.TargetProperty="Background.Color" From="Transparent" To="Blue" Duration="0:0:0.1" AutoReverse="True" RepeatBehavior="1x" /> 
        </Storyboard> 
       </VisualState> 
      </VisualStateGroup> 
     </VisualStateManager.VisualStateGroups> 
     <TextBox x:Name="txtBox" Text="{Binding DataContext.DisplayText, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}"/> 
    </Grid> 
</UserControl> 

Puede usar Visual State Groups para esto. Además, la propiedad de comportamiento y el valor pueden ser ambos de datos.

Hice esto rápidamente en combinación y no hice la prueba. esto es similar a mi solución.

<UserControl 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
      xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
      x:Class="WpfControlLibrary1.UserControl1" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
     <i:Interaction.Behaviors> 
      <ei:DataStateBehavior Binding="{Binding DataContext.IsTrue, 
        RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}" 
       Value="True" 
       TrueState="TrueState"/> 
     </i:Interaction.Behaviors> 
     <VisualStateManager.VisualStateGroups> 
      <VisualStateGroup x:Name="VisualStateGroup"> 
       <VisualState x:Name="DefaultState"/> 
       <VisualState x:Name="TrueState"> 
        <Storyboard Storyboard.TargetName="txtBox" > 
         <ColorAnimation Storyboard.TargetProperty="Background.Color" From="Transparent" To="Blue" Duration="0:0:0.1" AutoReverse="True" RepeatBehavior="1x" /> 
        </Storyboard> 
       </VisualState> 
      </VisualStateGroup> 
     </VisualStateManager.VisualStateGroups> 
     <TextBox x:Name="txtBox" Text="{Binding DataContext.DisplayText, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}"/> 
    </Grid> 
</UserControl> 
Cuestiones relacionadas