2009-03-20 10 views
1

Ich entwickle eine XBAP und ich habe eine einfache Anforderung.WPF - bester Weg, auf Seite/Fensterebene in einem Ansichtsmodell auf Veränderungen reagieren

Die DataContext der gesamten Hauptseite wird auf eine Instanz meiner UserViewModel gesetzt. Die UserViewModel hat eine DependencyProperty namens AuthenticationState, die eine Enum mit Werten wie 'Authenticated', 'NotAutheticated' und 'AuthenticationFailed' ist.

Nun, ich brauche durch Ausblenden/Anzeigen verschiedene Elemente auf der Seite zu einer Änderung dieses Wert zu reagieren.

Was (und wo) ist der beste Weg, dies zu tun?

Antwort

0

Verwaltet, um es mithilfe von Stilen zu sortieren. Es ist ein Schmerz, aber es funktioniert!

Die vollständige Quelle ist unten.

<Grid x:Name="contentGrid" Grid.Row="1"> 
     <!--login--> 
     <controls:LoginControl> 
      <controls:LoginControl.Style> 
       <Style> 
        <Setter Property="Control.Opacity" Value="0"/> 
        <Setter Property="Control.IsHitTestVisible" Value="False"/> 
        <Style.Triggers> 
         <DataTrigger Binding="{Binding Source={StaticResource UserViewModel},Path=UserAuthenticationState}" 
            Value="{x:Static model:AuthenticationState.NotAuthenticated}"> 
          <Setter Property="Control.IsHitTestVisible" Value="True"/> 
          <DataTrigger.EnterActions> 
           <BeginStoryboard> 
            <Storyboard> 
             <DoubleAnimation To="1" Duration="0:0:2" 
                 Storyboard.TargetProperty="Opacity"></DoubleAnimation> 
            </Storyboard> 
           </BeginStoryboard> 
          </DataTrigger.EnterActions> 
          <DataTrigger.ExitActions> 
           <BeginStoryboard> 
            <Storyboard> 
             <DoubleAnimation To="0" Duration="0:0:2" 
                 Storyboard.TargetProperty="Opacity"></DoubleAnimation> 
            </Storyboard> 
           </BeginStoryboard> 
          </DataTrigger.ExitActions> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </controls:LoginControl.Style> 
     </controls:LoginControl>  

     <!--slider--> 
     <slider:PageSlider> 
      <Button>1</Button> 
      <Button>2</Button> 
      <Button>3</Button> 
      <slider:PageSlider.Style> 
       <Style> 
        <Setter Property="Control.Opacity" Value="0"/> 
        <Setter Property="Control.IsHitTestVisible" Value="False"/> 
        <Style.Triggers> 
         <DataTrigger Binding="{Binding Source={StaticResource UserViewModel},Path=UserAuthenticationState}" 
            Value="{x:Static model:AuthenticationState.Authenticated}"> 
          <Setter Property="Control.IsHitTestVisible" Value="True"/> 
          <DataTrigger.EnterActions> 
           <BeginStoryboard> 
            <Storyboard> 
             <DoubleAnimation To="1" Duration="0:0:2" 
                 Storyboard.TargetProperty="Opacity"></DoubleAnimation> 
            </Storyboard> 
           </BeginStoryboard> 
          </DataTrigger.EnterActions> 
          <DataTrigger.ExitActions> 
           <BeginStoryboard> 
            <Storyboard> 
             <DoubleAnimation To="0" Duration="0:0:2" 
                 Storyboard.TargetProperty="Opacity"></DoubleAnimation> 
            </Storyboard> 
           </BeginStoryboard> 
          </DataTrigger.ExitActions> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </slider:PageSlider.Style> 
     </slider:PageSlider> 
    </Grid> 
+0

Sie möchten einen Auslöser, der das Steuerelement minimiert wenn die Deckkraft 0 ist. – Steven

0

Der beste Weg wäre, einen DataTrigger zu verwenden. So etwas wie folgt aus:

<Window.Triggers> 
    <DataTrigger Binding="{Binding AuthenticationState}" Value="NotAuthenticated"> 
     <Setter TargetName="nameOfControl" Property="Visibility" Value="Collapsed" /> 
    </DataTrigger> 
    ... 
    <TextBox x:Name="nameOfControl" /> 
</Window.Triggers> 

Solange Sie in der Datacontext des Window-Objekts UserViewModel dann sollte diese Arbeit!

+0

Ich kann das nicht tun. Window ist ein FrameworkElement, das nur EventTriggers in seiner Trigger-Sammlung akzeptiert. – Stimul8d

+0

Das ist ein guter Punkt, ich habe das vergessen. Ich stoße selten auf dieses Problem, weil alles, was ich mache, in Control/DataTemplates gemacht wird. – Steven

3

Wie Sie erwähnten Sie keine Datatrigger direkt auf einem Steuerelement verwenden können. Eine Umgehung wäre, einen Stil für jedes Steuerelement zu verwenden, der ausgeblendet werden muss.

<Grid> 
    <Rectangle Fill="Red" /> 
    <Grid.Style> 
     <Style TargetType="Grid"> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding Test}" Value="true"> 
        <Setter Property="Visibility" Value="Collapsed" /> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </Grid.Style> 
</Grid> 
+0

Sie können den Stil auch auf Ihrem Fenster wie in Ihrer anderen Antwort festlegen und Setter.TargetName verwenden. Auf diese Weise haben Sie 1 Trigger und viele Setter. –

+0

Ich wäre sehr überrascht, wenn das funktionieren würde, weil ich nicht denke, dass der TargetName aufgelöst würde, da der Kontext, den der Trigger verwendet, ist. – Steven

2

Ein bevorzugtes Verfahren wäre, einen Konverter zu verwenden „AuthenticationStateToVisibilityConverter“ genannt, die bei der Bindung der Eigenschaft Sichtbarkeit der Kontrolle an den Datenkontext des AuthenticationState Eigenschaft verwendet wird.

+0

lol. Sollte das entdeckt haben! Kannst du nicht sagen, es ist 5 Uhr an einem Freitag? – Stimul8d

0

Eigentlich ist der beste Weg, dies zu tun ist, die entsprechenden Eigenschaften aus Ihrer Sicht Modell zu belichten. Dies macht Ihre Logik zentralisierter und einfacher zu testen. Außerdem ist es besser als Konverter. Es ist schließlich ein Betrachtungsmodell. Daher sollte es die Ansicht modellieren. Wenn die Ansicht eine Eigenschaft benötigt, um anzugeben, wann ein Bereich ausgeblendet/angezeigt werden soll, fügen Sie eine solche Eigenschaft zu Ihrem Ansichtsmodell hinzu.

+0

Ich habe versucht, das zu tun, aber wo ist der Haken in diese Eigenschaft? Wessen Trigger-Sammlung kann ich verwenden, um den Wechsel durchzuführen? – Stimul8d

+0

Verwenden von DependencyObjects (und DependencyProperty) für Ansichtsmodelle ist eine schlechte Praxis IMHO. Es ist viel besser, POCOs zu verwenden, die INotifyPropertyChanged implementieren. Das heißt, Sie können DependencyPropertyDescriptor.AddValueChanged() verwenden, um auf Änderungen zu warten. –

+0

Sie werden schnell eine Explosion von Eigenschaften wie "ShowViewModel" haben. Dann haben Sie Fälle, in denen Sie nicht dieselbe ViewModel-Instanz an mehr als einer Stelle haben können, da ein unterschiedliches erwartetes Verhalten für verschiedene Szenerien besteht. Ein Konverter ist wartbar und das Testen ist genauso einfach. – Steven

Verwandte Themen