2009-06-15 23 views
3

Je suis en train de concevoir un contrôle utilisateur WPF qui contient d'autres contrôles utilisateur (imaginez un WidgetContainer, contenant différents Widgets) - en utilisant l'architecture M-V-VM. Pendant le développement, j'ai WidgetContainerView dans une fenêtre, la fenêtre (View) engendre un WidgetContainerViewModel comme ressource, et dans un constructeur sans paramètre de WidgetContainerViewModel, je remplis sa collection exposée avec quelques exemples de widgets (WidgetViewModels).Conception de WPF UserControl qui obtient son DataContext à partir des contrôles externes: Comment avoir des exemples de données dans le concepteur mais utiliser un contrôleur de domaine hérité au moment de l'exécution?

Le contrôle WidgetContainer hérite de la fenêtre DataContext, et à l'intérieur, il y a un ListView, qui lie Widgets au contrôle WidgetView (qui se trouve dans ListView.ItemTemplate). Maintenant, cela fonctionne correctement dans mon WindowView, car je vois mes exemples de widgets, mais une fois que j'ai édité le WidgetContainerView ou WidgetView, il n'y a pas de contenu - au moment de la conception, les contrôles sont autonomes et n'héritent aucun DataContext, donc je ne vois pas de contenu, et j'ai du mal à les concevoir (un ListView est vide, les champs de Widget aussi ...).

J'ai essayé d'ajouter un widget échantillon à la WidgetView:

public partial class WidgetView : UserControl 
{ 
    public WidgetView() 
    { 
     InitializeComponent(); 
     if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) 
     { 
      //btw, MessageBox.Show(...) here sometimes crashes my Visual Studio (2008), but I have seen the message - this code gets executed at design time, but with some lag - I saw the message on reload of designer, but at that time, I have already commented it - wtf? 
      this.DataContext = new WidgetViewModel(); //creates sample widget 
     } 
    } 
} 

mais cela ne fonctionne pas - je ne vois toujours pas quoi que ce soit dans le concepteur.

Je voulais aussi créer un WidgetViewModel comme ressource dans WidgetView, comme ceci:

<UserControl x:Class="MVVMTestWidgetsControl.View.WidgetView" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    DataContext="WidgetViewModel" //this doesn't work! 
    Height="Auto" Width="Auto"> 
    <UserControl.Resources> 
     <ResourceDictionary> 
      <ViewModel:WidgetViewModel x:Key="WidgetViewModel" /> 
     </ResourceDictionary> 
    </UserControl.Resources> 

    <TextBlock Text="{Binding Path=Title}"></TextBlock> 

</UserControl> 

mais je ne sais pas comment assigner un WidgetViewModel comme DataContext d'un widget tout - je ne peux pas Ajoutez l'attribut DataContext à UserControl, car WidgetViewModel est défini plus tard dans le code. Des idees pour faire cela? Je pourrais utiliser un échantillon de données de cette façon, et juste le remplacer dans le code afin qu'il ait le bon contenu à l'exécution ...

Quelles sont vos meilleures pratiques lors du développement de contrôles utilisateur? Merci, concevoir un contrôle vide n'est pas amusant :)).

Répondre

3

Dans votre deuxième extrait, vous devriez être en mesure de se référer à votre DataContext comme DynamicResource:

DataContext="{DynamicResource WidgetViewModel}" 

Mais la plupart des contrôles utilisateur personnalisés ont une sorte de conteneur de présentation de haut niveau, et vous pouvez régler le DataContext sur ce conteneur en tant que StaticResource.

Dans votre cas, cependant, vous pouvez envisager d'abandonner complètement la partie VM de votre code puisque vous écrivez un UserControl personnalisé. Vous devriez vous demander quels sont les avantages que vous obtenez d'un ViewModel complètement autonome, sans véritable support, conçu pour une seule vue (c'est-à-dire le UserControl personnalisé). Peut-être pourriez-vous simplement définir DependencyProperties et les utiliser?

+0

Merci, cela a bien fonctionné (même si je préfère préfère une solution qui ne changerait pas du tout programme lors de l'exécution). –

1

je suis venu avec plusieurs solutions: Ajouter DC en tant que ressource (il s'instancié automatiquement avec le constructeur parameterless), et procédez comme suit dans le codebehind Vue:

public PanelView() 
    { 
     InitializeComponent(); 

     if (!DesignerProperties.GetIsInDesignMode(new DependencyObject())) //DeleteAtRelease: 
     { 
      //we are in runtime, reset DC to have it inherited 
      this.DataContextHolder.DataContext = DependencyProperty.UnsetValue; 
     } 

    } 

Une meilleure façon serait seulement affecter DC si nous sommes au moment du design, mais VS ne l'a pas aimé - cela n'a fonctionné que de temps en temps, et de manière non déterministe, et une fois il s'est même écrasé.

Autre vérification pour le temps de conception est:

 if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) 
     { 
      this.DataContext = new WidgetViewModel(); 
     }