2010-03-08 9 views
14

Tengo un modelo de vista con una propiedad Fields que es ObservableCollection<FieldVM>. En la vista que utiliza esta propiedad, tengo una ItemsControl así:Alternativa DataTemplate.DataType en Silverlight

... 
<ItemsControl ItemsSource="{Binding Fields}" /> 
... 

FieldVM es una clase abstracta, implementado por tales clases como TextFieldVM y EnumFieldVM. Durante el tiempo de ejecución, estas FieldVM -implementaciones se agregan a la propiedad Fields y quiero que aparezcan en mi vista con sus vistas asociadas.

En WPF, hacer esto es simple, lo hago todo el tiempo. Usted acaba de hacer esto en un diccionario de recursos apropiados, y todo funciona como se espera:

<DataTemplate DataType="{x:Type vm:TextFieldVM}"> 
    <v:TextFieldView /> 
</DataTemplate> 

<DataTemplate DataType="{x:Type vm:EnumFieldVM}"> 
    <v:EnumFieldView /> 
</DataTemplate> 

Ahora, trabajando en Silverlight, por primera vez, esperaba que yo podría hacer lo mismo, pero el DataTemplate no tienen una propiedad DataType. Estoy perplejo. ¿Cuál es la forma de Silverlight de hacer esto?

Respuesta

7

utilizar un convertidor de valores a vincular el tipo de la visibilidad de cada punto de vista:

<DataTemplate> 
    <Grid> 
     <v:EnumFieldView 
      Visibilty="{Binding Converter={StaticResource ViewVisibilityConverter}, ConverterParameter=Enum}" /> 
     <v:TextFieldView 
      Visibilty="{Binding Converter={StaticResource ViewVisibilityConverter}, ConverterParameter=Text}" /> 
    </Grid 
</DataTemplate> 

Y en el ConvertTo del ViewVisibilityConverter, cambiar la visibilidad en función del tipo.

Otra forma de verlo sería usar un tipo diferente de convertidor de valor para devolver una plantilla de datos diferente de Application.Resources.

<ListBox ItemTemplate="{Binding Converter={StaticResource ItemTemplateFactory}"/> 

en ItemTemplateFactory.Convert():

var fieldVM = value as FieldVM; 

switch fieldVM.FieldType: 
{ 
    case "Text": 
     return Application.Current.Resources["TextTemplate"] as DataTemplate; 

    case "Enum": 
     return Application.Current.Resources["EnumTemplate"] as DataTemplate; 

} 
+3

Gracias por su sugerencia. Funciona, y lo estoy marcando como la respuesta, pero en realidad no es una solución ideal ... es más un hack feo. No puedo evitar sentir que tiene que haber una forma más adecuada de hacerlo, como la WPF. – Alex

+0

Agregué una opción adicional que podría ser un poco más bonita: –

+0

@Alex: me doy cuenta de que llegué un año tarde al juego aquí, pero implementé un comportamiento adjunto 'BooleanVisibility' que podría resultarle interesante. Puede encontrar la reseña aquí: http://www.executableintent.com/attached-behaviors-part-1-booleanvisibility/. La Parte 2 de la serie tiene un ejemplo de código con un marco de comportamiento adjunto y la implementación 'BooleanVisibility'. –

3

Silverlight no tiene un DataTemplateSelector pero he usado este fragmento ...

<ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <client:TemplateSelector Content="{Binding}"/> 
    </DataTemplate> 
</ItemsControl.ItemTemplate> 

Aquí está el selector de plantilla:

public class TemplateSelector : ContentControl 
{ 
    protected override void OnContentChanged(object oldContent, object newContent) 
    { 
     base.OnContentChanged(oldContent, newContent); 

     MyObject f = newContent as MyObject; 

     switch (f.MyProperty) 
     { 
      case "Bool": 
      case "String": 
      case "Array": 
      default: 
       ContentTemplate = Application.Current.Resources["MultiSelectDataTemplate"] as DataTemplate; 
       break; 
     } 
    } 
} 
+0

DataTemplateSelector no está disponible en Silverlight tampoco ... Pero he visto algunos intentos para implementar esta clase en Silverlight. Aquí hay uno: http://skysigal.xact-solutions.com/Blog/tabid/427/EntryId/1000/Silverlight-a-port-of-the-DataTemplateSelector.aspx –

+0

DataTemplateSelector no es parte de Silverlight 4 – Jehof

+0

Usted 'estas en lo correcto. Utilicé otro fragmento como reemplazo. Edición. – funwhilelost

4

Una variante en la segunda opción de Michael (ya que no pude hacerlo funcionar directamente).

En recursos definir un DataTemplate adicional:

<DataTemplate x:Key="DynamicTemplate"> 
    <ContentPresenter ContentTemplate="{Binding Converter={StaticResource TemplateChooser}}" Content="{Binding}"/> 
</DataTemplate> 

y luego utilizar esta plantilla de datos en el cuadro de lista

<ListBox ItemTemplate="{StaticResource DynamicTemplate}"> 

TemplateChooser debe ser un IValueConvertor, donde la función de conversión toma un objeto y devuelve el DataTemplate que se debe usar para ese objeto.

+0

No es una respuesta completa, pero es un buen consejo para el control de elementos. –

8

Microsoft Prism library tiene aplicación DataTemplateSelector encargo, nombres de las clases notar en DataTemplate x: claves:

    <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <prism:DataTemplateSelector Content="{Binding}" HorizontalContentAlignment="Stretch" IsTabStop="False"> 
          <prism:DataTemplateSelector.Resources> 
           <DataTemplate x:Key="OpenQuestionViewModel"> 
            <Views:OpenQuestionView DataContext="{Binding}"/> 
           </DataTemplate> 

           <DataTemplate x:Key="MultipleSelectionQuestionViewModel"> 
            <Views:MultipleSelectionView DataContext="{Binding}"/> 
           </DataTemplate> 

           <DataTemplate x:Key="NumericQuestionViewModel"> 
            <Views:NumericQuestionView DataContext="{Binding}"/> 
           </DataTemplate> 
          </prism:DataTemplateSelector.Resources> 
         </prism:DataTemplateSelector> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
-4

¿Has probado a descuidar la propiedad Tipo de datos? y acaba de escribir algo como esto:

<DataTemplate> 
    <v:TextFieldView /> 
</DataTemplate> 

trabajó para mí

+0

El objetivo de la propiedad 'DataType' es permitir la selección dinámica de plantillas: se utiliza la plantilla que se aplica al tipo de datos apropiado y se ignoran las demás. En su respuesta, el TetxFieldView se usará siempre. –

5

Silverlight 5, finalmente incluirá esta funcionalidad. Hasta entonces, la respuesta marcada es una de las mejores formas que he visto.

+1

... y desde que se envió Silverlight 5, ya no necesita este tipo de solución. Tienes que omitir el bit {x: Type} y solo especificar el nombre del tipo. –

0

Esta publicación de blog: http://www.c-sharpcorner.com/Blogs/1937/ presenta lo que parece ser un buen selector de plantilla de datos para hágalo usted mismo disfrazado como un convertidor de valor. Tiene la ventaja de que no hay necesidad de instalar Prism.