2016-07-07 23 views
1

Ich versuche, die Farbe eines Rechtecks ​​(WPF) mit Trigger zu setzen, auf einem boolean DependencyProperty abhängig, die ich an der Tag-Eigenschaft des Rechtecks ​​bin verbindlich.Auslöser funktioniert nicht, wenn Bindungseigenschaft dependecyproperty

Ich habe den folgenden Code:

public partial class MainWindow : Window 
{ 
    public Boolean isAutoStart 
    { 
     get { return (Boolean)GetValue(isAutoStartProperty); } 
     set { SetValue(isAutoStartProperty, value); } 
    } 

    public static readonly DependencyProperty isAutoStartProperty = 
     DependencyProperty.Register("isAutoStart", typeof(Boolean), 
     typeof(MainWindow), new PropertyMetadata(true)); 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     isAutoStart = false; 
    } 
} 

und in XAML:

<Window.Resources> 
    <Style x:Key="TriggerDark" TargetType="Rectangle"> 
     <Setter Property="Fill" Value="Green" /> 
     <Style.Triggers> 
      <Trigger Property="Tag" Value="False"> 
       <Setter Property="Fill" Value="Red" /> 
      </Trigger> 
      <Trigger Property="Tag" Value="True"> 
       <Setter Property="Fill" Value="Green" /> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 

</Window.Resources> 

<Rectangle Style="{StaticResource ResourceKey=TriggerDark}" Tag="{Binding Path=isAutoStart, UpdateSourceTrigger=PropertyChanged}"> 

Wenn ich "True" oder "False" in die Tag-Eigenschaft des Rechtecks ​​codieren, arbeiten die Auslöser richtig . Und wenn ich den Wert der Tag-Eigenschaft auf Laufzeit zur Konsole drucken, funktioniert die Bindung, aber die Auslöser werden nicht ausgelöst.

Irgendwelche Ideen, was ich falsch mache?

Danke!

+1

Die Bindung wird nicht funktionieren, wenn Sie ein Quellobjekt gesetzt, z.B. indem Sie den DataContext des Fensters auf sich selbst setzen oder die RelativeSource-Eigenschaft der Binding angeben. Außerdem macht das Setzen von UpdateSourceTrigger keinen Sinn, da es hier keinen Effekt hat. – Clemens

+1

Es kann auch sinnvoll sein, die Tag-Eigenschaft nicht zu binden und einen Trigger auf ihren Wert festzulegen, sondern stattdessen einen DataTrigger zu verwenden, der direkt an die isAutoStart-Eigenschaft bindet. – Clemens

+0

Falls Sie den DataContext nicht gesetzt haben, versuchen Sie 'Tag =" {Binding isAutoStart, RelativeSource = {RelativeSource AncestorType = Window}} ". – Clemens

Antwort

2

Ihre Trigger versuchen, den boolean true mit der Zeichenfolge „True“ zu vergleichen, weil Tag eine Objekt-Eigenschaft ist, so dass der boolean gespeichert wird, während der Wert Ihrer Trigger-ein String ist. PHP würde es mögen, nicht WPF. ;)

Wenn Sie den Auslöser anstelle eines Datatrigger Sie eine statische Klasse erstellen können behalten möchten:

public static class BooleanHelper { 
    public static bool False { 
     get { return false; } 
    } 
    public static bool True { 
     get { return true; } 
    } 
} 

Und dann wird die Art geschrieben werden als:

<Style x:Key="TriggerDark" TargetType="Rectangle"> 
    <Setter Property="Fill" Value="Green"/> 
    <Style.Triggers> 
     <Trigger Property="Tag" Value="{x:Static local:BooleanHelper.True}"> 
      <Setter Property="Fill" Value="Red" /> 
     </Trigger> 
    </Style.Triggers> 
</Style> 

Credit Michael Mairegger auf die Idee.

+0

Danke, das funktioniert perfekt. :) – Niki

1

Sie könnten versuchen, einen Datatrigger mit:

(Beachten Sie, dass Sie auch Ihren Stil semplify, einen Auslöser zu entfernen)

 <Style x:Key="TriggerDark" TargetType="Rectangle"> 
      <Setter Property="Fill" Value="Green" /> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding Path=isAutoStart}" Value="False"> 
        <Setter Property="Fill" Value="Red" /> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 

Rahmen auch die Datacontext zum Fenster:

public MainWindow() 
{ 
    DataContext = this; 
} 

EDIT: Wenn Sie möchten, dass Sie eine IValueConverter verwenden können:

public class BoolToStringConverter : IValueConverter 
{ 

    public object Convert(object value, Type targetType, object parameter, 
     System.Globalization.CultureInfo culture) 
    { 
     if (targetType != typeof(bool)) 
      throw new InvalidOperationException("The target must be a boolean"); 

     return value.ToString(); 
    } 

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

} 

und die Bindung ändern:

<Window.Resources> 
     <local:BoolToStringConverter x:Key="BtSConv"/> 
     <Style x:Key="TriggerDark" TargetType="Rectangle"> 
      <Setter Property="Fill" Value="Green" /> 
      <Style.Triggers> 
       <Trigger Property="Tag" Value="False"> 
        <Setter Property="Fill" Value="Red" /> 
       </Trigger> 
      </Style.Triggers> 
     </Style> 

    </Window.Resources> 
    <Rectangle Style="{StaticResource TriggerDark}" Tag="{Binding isAutoStart, Converter={StaticResource BtSConv}}" /> 

Auch gibt es viele schöne Lösung für Sie von den anderen.

+0

Ich möchte die Abhängigkeitseigenschaft nicht direkt mit einem DataTrigger binden, da ich dies wiederverwenden möchte "Vorlage" und übergeben Sie einfach eine andere Abhängigkeitseigenschaft innerhalb der Tag-Eigenschaft. – Niki

1

Sie benötigen die DataContext Ihrer Bindung zu setzen. Im Moment zeigt Ihre Bindung auf Rectangle.DataContext.isAutoStart, Rectangle.DataContext ist jedoch null, also löst sich Ihre Bindung nicht in irgendetwas auf. Weitere Informationen zur DataContext finden Sie unter this answer.

Weil Du here erwähnt wollen Sie nicht mit einem DataTrigger hart codieren, wahrscheinlich werden Sie wollen manuell die Source Ihre Bindung, um die visuelle Struktur mit dem ersten Window Objekt statt zu suchen, und binden an das isAutoStart Eigentum Das.

<Rectangle Tag="{Binding Path=isAutoStart, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" .. /> 

Sie haben auch das zusätzliche Problem, wie durch this answer wiesen darauf hin, in dem Sie eine boolean in einen String vergleichen, so wird es immer als falsch zu bewerten. Es gibt viele Möglichkeiten, um dieses, wie ein IValueConverter, aber ich finde das einfachste System-Namespace importieren und einen statischen Wert für boolean true erstellen, wie here gezeigt:

<s:Boolean x:Key="TrueValue">True</s:Boolean> 
... 
<Trigger Property="Tag" Value="{StaticResource TrueValue}"> 

wo der s Namespace als

definiert
xmlns:s="clr-namespace:System;assembly=mscorlib" 
1

Benutzer nkoniishvt bereits die Erklärung gegeben hat, vergleicht der Auslöser der Tag Eigenschaftswert auf den Stringliterale „True“ und „false“ anstelle der bool Werte.

Eine alternative Problemumgehung für dieses Problem möglicherweise nicht die Tag-Eigenschaft verwenden, aber eine ordnungsgemäß typisierte angefügte Eigenschaft, deklariert z. als

public static class StyleHelper 
{ 
    public static readonly DependencyProperty StateProperty = 
     DependencyProperty.RegisterAttached(
      "State", typeof(bool), typeof(StyleHelper)); 

    public static bool GetState(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(StateProperty); 
    } 

    public static void SetState(DependencyObject obj, bool value) 
    { 
     obj.SetValue(StateProperty, value); 
    } 
} 

Sie es in XAML wie folgt verwenden würde:

<Window.Resources> 
    <Style TargetType="Rectangle"> 
     <Setter Property="Fill" Value="Green" /> 
     <Style.Triggers> 
      <Trigger Property="local:StyleHelper.State" Value="False"> 
       <Setter Property="Fill" Value="Red" /> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 
</Window.Resources> 

<Rectangle local:StyleHelper.State="{Binding isAutoStart}}" />