2010-04-02 5 views
7

Ho realizzato un esempio di esempio di esempio VS 2010 RC, perché nel mio progetto di produzione ho lo stesso errore utilizzando MVVM.ContentTemplateSelector viene chiamato una sola volta e mostra sempre lo stesso datatemplate

Nel mio progetto di esempio demo Io uso solo Codice-dietro senza 3rd dipendenze del partito in modo da poter scaricare il progetto demo qui e correre in prima persona: http://www.sendspace.com/file/mwx7wv

Ora per il problema: Quando scatto delle ragazze/ragazzi pulsante dovrebbe cambiare il datatemplate, no?

Cosa ho sbagliato?

OK Offro qui un frammento di codice troppo:

codice sottostante 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: classe

<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> 

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

Better frammenti di codice postale invece di offrire un download , le persone probabilmente non scaricheranno tha t. –

+1

ok modificato il mio post di init! – msfanboy

+1

ok dopo alcune ricerche: http://joshsmithonwpf.wordpress.com/2007/03/18/updating-the-ui-when-binding-directly-to-business-objects-that-are-modified/ come Josh ha detto nei suoi commenti di codice: "... Questo è necessario perché il sistema vincolante WPF ignorerà un \t \t \t // PropertyChanged notifica se la proprietà restituisce lo stesso riferimento a un oggetto come prima ..." non devo restituire lo stesso oggetto invece devo ricreare l'oggetto Person nel gestore di pulsanti come: ... = new Person() {IsBoy = true, IsGirl = falso} ecc ... quindi funziona. grazie josh! – msfanboy

risposta

5

Mi piace la soluzione di Neil (che si trova sulla via Josh's postthe 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: non ho potuto realmente ottenere il codice di cui sopra per lavorare, ma questo funziona utilizzando uno stile:


 <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

Nota:: Penso che questo metodo sia piuttosto goffo, ma potrebbe funzionare per alcuni scenari. Sono favorevole al metodo di utilizzo di un trigger (da Neil) che ho postato come risposta separata.


Un altro modo possibile è di impegnare la Content del ContentTemplateSelector alla proprietà che determina il modello che dovrebbe essere selezionato. Per esempio qui ho due diverse barre degli strumenti scelti in base al valore di SourceSystem. Ho impostato Content come proprietà del sistema stesso.

<ContentControl ContentTemplateSelector="{StaticResource toolbarTemplateSelector}" 
       DataContext="{Binding}" Content="{Binding SourceSystem}" /> 

Il selettore modello visualizza semplicemente il sistema di origine e restituisce il modello necessario.

Se il modello richiede l'accesso al datacontext del controllo, è sufficiente utilizzare il collegamento elemento per impostarlo.

<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

Utilizzare questo metodo per Selector contenuti personalizzati:

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

in 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> 

E 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

Anche se in qualche modo corretto, non consente di eseguire * binding di contenuto al ** oggetto completo *** come in '' pur consentendo al selettore _template di ** osservare cose diverse ** rispetto a content_, come '.IsBoy' vs' .IsGirl 'come nella domanda. – quetzalcoatl

Problemi correlati