2010-04-02 3 views
7

J'ai fait un exemple de projet de démonstration VS 2010 RC, parce que dans mon projet de production j'ai la même erreur en utilisant MVVM.ContentTemplateSelector est seulement appelé une fois montrant toujours le même datatemplate

Dans mon exemple de projet de démonstration que j'utilise uniquement le code-behind sans dépendances 3ème partie afin que vous pouvez télécharger le projet de démonstration ici et l'exécuter pour vous-même: http://www.sendspace.com/file/mwx7wv

maintenant au problème: Lorsque je clique sur les filles/garçons bouton il devrait changer le datatemplate, pas?

Qu'est-ce que je me trompe?

OK Je propose ici un extrait de code trop:

code-behind MainWindow.cs:

namespace ContentTemplateSelectorDemo 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     Person person; 

     public MainWindow() 
     { 
      InitializeComponent(); 

      person = new Person(){ Gender = "xxx"}; 
      person.IsBoy = true; 


      ContentGrid.DataContext = person; 
     } 

     private void btnBoys_Click(object sender, RoutedEventArgs e) 
     { 
      person.IsBoy = true; 
      person.IsGirl = false; 
      this.ContentGrid.DataContext = person; 
     } 

     private void btnGirls_Click(object sender, RoutedEventArgs e) 
     { 
      person.IsGirl = true; 
      person.IsBoy = false; 
      this.ContentGrid.DataContext = person; 

     }   
    } 
} 

XAML MainWindow.xaml:

<Window x:Class="ContentTemplateSelectorDemo.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:ContentTemplateSelectorDemo" 
     Title="MainWindow" Height="350" Width="525"> 

    <Window.Resources> 

     <DataTemplate x:Key="girlsViewTemplate"> 
      <local:UserControl1 /> 
     </DataTemplate> 

     <DataTemplate x:Key="boysViewTemplate" > 
      <local:UserControl2 /> 
     </DataTemplate> 

     <local:PersonDataTemplateSelector x:Key="PersonSelector" /> 

    </Window.Resources> 

    <Grid x:Name="ContentGrid" > 
     <StackPanel> 
      <Button Name="btnGirls" Click="btnGirls_Click">Switch Girls</Button> 
      <Button Name="btnBoys" Click="btnBoys_Click">Switch Boys</Button> 
     <ContentControl Content="{Binding}" ContentTemplateSelector="{StaticResource ResourceKey=PersonSelector}" /> 
     </StackPanel> 
    </Grid> 
</Window> 

classe DataTemplateSelector :

public class PersonDataTemplateSelector : DataTemplateSelector 
{ 
    public override DataTemplate SelectTemplate(object item,DependencyObject container) 
    { 
     if (item is Person) 
     { 
      Person person = item as Person; 

      Window window = Application.Current.MainWindow; 

      if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(window)) 
       return null; 

      if (person.IsBoy)    
       return window.FindResource("boysViewTemplate") as DataTemplate; 
      if (person.IsGirl)    
       return window.FindResource("girlsViewTemplate") as DataTemplate; 

     } 
     return null; 
    } 
} 

:)

+1

meilleurs extraits de code postal au lieu d'offrir un téléchargement , les gens ne vont probablement pas télécharger tha t. –

+1

ok édité mon article de départ! – msfanboy

+1

ok après quelques recherches: http://joshsmithonwpf.wordpress.com/2007/03/18/updating-the-ui-when-binding-directly-to-business-objects-that-are-modified/ comme josh dit dans ses commentaires de code: "... Ceci est nécessaire parce que le système de liaison WPF ignorera une notification \t \t \t // PropertyChanged si la propriété retourne la même référence d'objet que précédemment ..." Je ne dois pas retourner le même objet à la place je dois recréer l'objet Person dans le eventhandler de boutons comme: ... = new Personne() {IsBoy = vrai, IsGirl = faux} etc ... alors ça marche. merci josh! – msfanboy

Répondre

5

J'aime la solution de Neil (qui se trouve sur Josh's post via the link you provided):

<DataTemplate DataType="{x:Type local:MyType}"> 
     <ContentPresenter Content="{Binding}" Name="cp" /> 
     <DataTemplate.Triggers> 
      <DataTrigger Binding="{Binding Path=IsRunning}" Value="True"> 
       <Setter TargetName="cp" Property="ContentTemplate" Value="{StaticResource StopTemplate}" /> 
      </DataTrigger> 
      <DataTrigger Binding="{Binding Path=IsRunning}" Value="False"> 
       <Setter TargetName="cp" Property="ContentTemplate" Value="{StaticResource StartTemplate}" /> 
      </DataTrigger> 
     </DataTemplate.Triggers> 
    </DataTemplate> 

Edit: Je ne pouvais pas vraiment le code ci-dessus fonctionne, mais cela fonctionne utilisant un style:


 <DataTrigger Binding="{Binding Path=SourceSystem.SourceSystemName}" 
        Value="mysite.com"> 
    <Setter Property="ContentControl.ContentTemplate" 
        Value="{StaticResource mysiteToolbar}" /> 

 <DataTrigger Binding="{Binding Path=SourceSystem.SourceSystemName}" 
        Value="mysite2.com"> 
    <Setter Property="ContentControl.ContentTemplate" 
        Value="{StaticResource mysiteToolbar2}" /> 

</Style.Triggers>    

+0

http://stackoverflow.com/questions/5771362/wpf-how-to-set-the-data-template-trigger-for-content-control – invalidusername

3

Note: Je pense que cette méthode est assez maladroite, mais pourrait fonctionner pour certains scénarios. Je suis en faveur de la méthode d'utilisation d'un déclencheur (de Neil) que j'ai posté comme une réponse séparée.


Une autre possibilité consiste à lier le Content du ContentTemplateSelector à la propriété qui détermine le modèle qui doit être sélectionné. Par exemple ici j'ai deux barres d'outils différentes choisies en fonction de la valeur de SourceSystem. J'ai mis le Content pour être la propriété du système de sources elle-même.Le sélecteur de modèle regarde simplement le système source et renvoie le modèle nécessaire.

Si le modèle doit accéder au datacontext du contrôle, utilisez simplement la liaison d'élément pour le définir.

<UserControl.Resources> 
    <DataTemplate x:Key="toolbar1"> 
     <views:OrdersToolbar1View Margin="0,5,0,0" 
       DataContext="{Binding ElementName=control,Path=DataContext}"/> 
    </DataTemplate> 
    <DataTemplate x:Key="toolbar2"> 
     <views:OrdersToolbar2View Margin="0,5,0,0" 
       DataContext="{Binding ElementName=control,Path=DataContext}"/> 
    </DataTemplate> 
</UserControl.Resources> 
-2

Utilisez cette méthode pour sélecteur de contenu personnalisé:

private void ReloadContent() 
{ 
    MainContentControl.ContentTemplate = MainContentControl.ContentTemplateSelector.SelectTemplate(null, MainContentControl); 
} 

En XAML:

<ContentControl Content="{Binding}" x:Name="MainContentControl"> 
    <ContentControl.ContentTemplateSelector > 
      <templateSelectors:MainViewContentControlTemplateSelector> 
       <templateSelectors:MainViewContentControlTemplateSelector.BoysTemplate> 
        <DataTemplate> 
         <local:UserControl1 /> 
        </DataTemplate> 
        </templateSelectors:MainViewContentControlTemplateSelector.BoysTemplate> 
       <templateSelectors:MainViewContentControlTemplateSelector.GirlsTemplate> 
        <DataTemplate> 
         <local:UserControl2 /> 
        </DataTemplate> 
        </templateSelectors:MainViewContentControlTemplateSelector.GirlsTemplate> 
    </ContentControl> 

Et Selector:

public class MainViewContentControlTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate BoysTemplate{ get; set; } 
    public DataTemplate GirlsTemplate{ get; set; } 


    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     var contentControl = container.GetVisualParent<ContentControl>(); 
     if (contentControl == null) 
     { 
      return BoysTemplate; 
     } 

     if (//Condition) 
     { 
      return GirlsTemplate; 

     } 

     return BoysTemplate; 
    } 
+1

Bien que quelque peu correct, il ne vous permet pas de * effectuer des liaisons de contenu à l'objet complet ** comme dans 'tout en autorisant le sélecteur _template à ** observer autre chose que content_, comme' .IsBoy' vs '.IsGirl 'comme dans la question. – quetzalcoatl

Questions connexes