2010-04-02 4 views
7

He hecho una demostración de ejemplo VS 2010 RC proyecto de muestra, porque en mi proyecto de producción tengo el mismo error al usar MVVM.ContentTemplateSelector solo se llama una vez y muestra siempre la misma plantilla de datos

En mi proyecto de demostración muestra sólo uso de código subyacente, sin dependencias de 3 ª parte para que pueda descargar el proyecto de demostración aquí y ejecutarlo por sí mismo: http://www.sendspace.com/file/mwx7wv

ahora al problema: Al hacer clic en las niñas/niños botón debería cambiar la plantilla de datos, ¿no?

¿Qué es lo que me pasa?

Aceptar que ofrecemos aquí un fragmento de código también:

de código subyacente 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: Clase de

<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

mejores fragmentos de código postal en lugar de ofrecer una descarga , lo más probable es que la gente no vaya a descargar tha t. –

+1

ok editado mi publicación de inicio! – msfanboy

+1

bien después de algunas investigaciones: http://joshsmithonwpf.wordpress.com/2007/03/18/updating-the-ui-when-binding-directly-to-business-objects-that-are-modified/ como dijo Josh en sus códigos de comentarios: "... Esto es necesario debido a que el sistema de unión de WPF ignorará una \t \t \t // PropertyChanged notificación si la propiedad devuelve la misma referencia de objeto como antes ..." no debo devolver el mismo objeto en su lugar tengo que volver a crear el objeto Persona en los botones eventhandler como: ... = new Person() {IsBoy = true, IsGirl = false} etc ... entonces funciona. gracias josh! – msfanboy

Respuesta

5

me gusta la solución de Neil (que se encuentra en medio de 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> 

Editar: realidad no podría conseguir el código anterior para trabajar, pero esto funciona utilizando un estilo:


 <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: Creo que este método es bastante torpe, pero podría funcionar en algunos casos. Estoy a favor del método de usar un disparador (de Neil) que publiqué como una respuesta separada.


Otra forma posible es de obligar a la Content de la ContentTemplateSelector a la propiedad que determina la plantilla que debe ser seleccionado. Por ejemplo, aquí tengo dos barras de herramientas diferentes elegidas según el valor de SourceSystem. Establecí el Content como la propiedad del sistema de origen.

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

El selector de plantillas simplemente mira el sistema de origen y devuelve la plantilla necesaria.

Si la plantilla necesita acceso al contexto de datos del control, simplemente use el enlace de elementos para establecerlo.

<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

Utilice este método para selector personalizado Contenido:

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> 

Y 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

Aunque es algo correcto, no permite * realizar el enlace de contenido al ** objeto completo *** como en '' mientras permite que el selector _template ** observe algo diferente ** que contenido_, como '.IsBoy' vs' .IsGirl 'como en la pregunta. – quetzalcoatl

Cuestiones relacionadas