2010-10-05 20 views
1

J'essaie d'apprendre à séparer une vue de son modèle de vue associé, tout en rendant la vue aussi peu ou pas de code-behind que possible.comment faire un contrôle xaml avec différents modes d'affichage

mon contrôle a un bloc de texte lorsque l'objet est dans un mode d'affichage, et une zone de texte lorsque l'utilisateur veut modifier ce champ. Dans les deux cas, ces contrôles doivent se lier à la même chaîne dans le modelview, mais seulement celui qui convient doit être affiché en fonction de l'état du viewmodel. Auparavant, je modifiais simplement l'enfant des panneaux à un nouvel élément dans le codebehind ... mais si je comprends bien, je devrais essayer de faire tous mes changements dans XAML pour la vue.

Mon viewmodel a un bool dénotant si c'est en mode d'affichage ou d'édition. Existe-t-il un moyen de spécifier l'utilisation d'un modèle différent en fonction de la valeur de ce booléen, mais de le conserver en XAML?

+0

Pourquoi essayez-vous de faire cela? En d'autres termes, la directive de «faire toutes les modifications dans XAML» peut ne pas avoir de sens pour vous. Je vais vous fournir un échantillon de code, mais s'il semble plus compliqué ou moins facile à maintenir que quelque chose que vous comprenez complètement, alors vous vous faites du tort. –

+0

Je suis encore relativement nouveau à WPF, et je m'habitue à ce que l'on pourrait considérer comme des «meilleures pratiques» ... J'ai regardé un tutoriel montrant le modèle MVVM dans WPF, et une partie de ce qui en est sorti est le code derrière devrait être presque effacé ... que si vous le faites correctement, votre vue devrait être presque complètement XAML, et votre ViewModel devrait être découplé du code de vue ... donc, fondamentalement, j'explore différentes façons de mettre en place une interface qui pourrait changer en fonction de l'entrée de l'utilisateur. – tbischel

+0

Je sais que c'est ce qu'ils disent. Cependant, tous les consultants que j'ai rencontrés qui mettent ces choses en pratique rapportent l'agnosticisme de l'idée. À mon avis, il a été développé pour faciliter la vente d'Expression Blend aux équipes de concepteurs/développeurs hybrides dans les très grandes organisations. Peut-être que la pratique est la meilleure pour les projets de silo en équipe dans ce genre d'endroits. Mais pour les applications métiers, cela peut être une distraction massive. Je vais vous donner tout cela, cependant: vous apprendrez le balisage XAML complexe. Mais ne croyez pas une seconde que si c'est XAML, ce n'est pas du code. Tout est code. –

Répondre

3

Il existe un moyen de faire ce que vous dites sur lequel vous travaillez, en utilisant DataTriggers.

D'abord, définissez un Style qui contient les DataTrigger s que vous souhaitez utiliser. Par exemple, notez ici deux styles identiques pour un ContentControl, chacun avec une DataTrigger paire qui effectue le contraire de l'autre:

<Window.Resources> 
    <Style TargetType="{x:Type ContentControl}" x:Key="HiddenWhenFalse" > 
     <Setter Property="Visibility" Value="Collapsed"/> 
     <Style.Triggers> 
      <DataTrigger Value="False" Binding="{Binding MyBooleanValue}"> 
       <Setter Property="Visibility" Value="Collapsed" /> 
      </DataTrigger> 
      <DataTrigger Value="True" Binding="{Binding MyBooleanValue}"> 
       <Setter Property="Visibility" Value="Visible" /> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 


    <Style TargetType="{x:Type ContentControl}" x:Key="HiddenWhenTrue" > 
     <Setter Property="Visibility" Value="Visible"/> 
     <Style.Triggers> 
      <DataTrigger Value="True" Binding="{Binding MyBooleanValue}"> 
       <Setter Property="Visibility" Value="Collapsed" /> 
      </DataTrigger> 
      <DataTrigger Value="False" Binding="{Binding MyBooleanValue}"> 
       <Setter Property="Visibility" Value="Visible" /> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 
</Window.Resources> 

Ensuite, dans votre arbre principal visuel que vous définiriez ContentControl s qui utilisent ces Style s, et attribuez le DataContext du Window ou UserControl ou autre à votre ViewModel. Quelque chose comme ceci:

<Grid> 
    <StackPanel > 
     <Button Content="False" Name="Button2"></Button> 
     <Button Content="True" Name="Button1"></Button> 
     <ContentControl Style="{StaticResource HiddenWhenFalse}"> 
      <ContentControl.Content> 
       <TextBlock Text="ITS ALL TRUE"/> 
      </ContentControl.Content> 
     </ContentControl> 
     <ContentControl Style="{StaticResource HiddenWhenTrue}"> 
      <ContentControl.Content> 
       <TextBlock Text="ITS ALL FALSE"/> 
      </ContentControl.Content> 
     </ContentControl> 
    </StackPanel> 
</Grid> 

est le ViewModel Je suis ici en utilisant, notez la mise en œuvre de INotifyPropertyChanged:

Imports System.ComponentModel 

Public Class MainWindowViewModel 
    Implements INotifyPropertyChanged 
    Private _MyBooleanValue = False 
    Public Property MyBooleanValue 
     Get 
      Return _MyBooleanValue 
     End Get 
     Set(ByVal value) 
      _MyBooleanValue = value 
      RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Nothing)) 
     End Set 
    End Property 

    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged 
End Class 

Maintenant, aux fins de cet exemple, je simplement câblé les deux boutons Définissez la valeur ViewModel. Si vous voulez utiliser Commanding pour câbler des boutons, c'est un sujet entièrement différent. Il vaut la peine de discuter, mais pour des raisons de simplicité:

Class MainWindow 
    Private vm As New MainWindowViewModel 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click 
     vm.MyBooleanValue = True 
    End Sub 

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button2.Click 
     vm.MyBooleanValue = False 
    End Sub 

    Private Sub MainWindow_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded 
     Me.DataContext = vm 
    End Sub 
End Class 

Gardez à l'esprit que cet échantillon styles explicitement ContentControl, et que vous devrez changer le TargetType de votre style si vous travaillez avec un type ce n'est pas descendu de cette classe.