Débutant-confus au sujet de la reliure et des ressources dans WPF

j'essaie d'apprendre WPF mais je trouve très difficile de comprendre les reliures, la chose" ressources", et la création d'objet. Ma formation est en C++ / MFC et c#-Winforms.

mes questions:

  1. la plupart des exemples que je vois dans XAML (dans MSDN et dans deux autres livres de WPF que j'ai lus) utilisent StaticResource dans l'expression de reliure. Ces liés en aucune façon à des membres statiques? Ou est-ce juste un nom trompeur? Lorsqu'un référence est faite à n'importe quel objet comme une ressource statique, quand est-il instancié?

  2. autant que je puisse voir que les ressources statiques sont utilisées avec des "choses" définies dans la section "Ressources" de l'application/fenêtre/Contrôle, etc.

    Ces sections sur les ressources sont très confuses pour moi. Qu'est-ce exactement sont-ils? D'après mon expérience en MFC, ce sont des icônes, des cordes, etc. Cependant, à en juger par tous les exemples que j'ai vu, dans WPF ceux-ci semblent être essentiellement un "dépotoir" pour (a) toutes sortes de définitions globales d'objets dans le markup (styles, gabarits de données, etc) (b) toutes sortes d'objet global instanciations dans le balisage Suis-je la corriger? Cela me semble très salissant.

    Il s'agit essentiellement d'apprendre toutes sortes de semi-DSL dans XAML (pour définir les styles, pour définir les gabarits de données, pour créer des objets, etc.), et de les coller ensemble au même endroit. Je continuez à penser à quelque chose comme éditer le fichier de ressources (.rc) en MFC à la main. Au moins là les sections étaient bien séparées et la syntaxe pour chaque ressource était relativement simple.

  3. pour lier les deux questions précédentes: quand je définirai une instance objet dans la section Ressources, et plus tard la référencer à partir d'une liaison StaticResource, quand exactement est-elle instanciée? MSDN dit (dans "Comment faire: rendre les données disponibles pour la reliure dans XAML"):

une façon de faire l'objet disponible pour reliure est de le définir comme ressource

Cependant, ce n'est pas très clair. Que signifient-ils disponibles? Signifient-ils créés? Sont-ils connectés au sous-système de liaison? Et quand exactement cet objet a-t-il créé ? En jouant avec un exemple simple j'ai vu que WPF semble créer cet objet pour moi quand il essaie de joindre la liaison. Et c'est encore plus confus.

EDIT: Après la clarification par karmicpuppet ci-dessous, je suis encore confus quant à la façon dont cela est lié à la reliure. Supposons que j'ai dans mes ressources:

<local:Person x:Key="MyPerson" Name="Title"/> 

(où personne est une classe avec une propriété appelée nom) et puis dans la fenêtre j'ai:

<TextBlock Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/> 

1) qu'est-ce que cela fait? Est-il passe par les mêmes étapes - la recherche de la et l'appliquer ensuite à la propriété Text? Est-ce que L'objet MyPerson est créé au moment de la création de la fenêtre, ou plus tard? 2) est-ce que je dois utiliser le mécanisme de liaison pour me lier à la propriété du nom? Je ne peux pas m'y attacher directement comme tu l'as fait avec myBrush? Pourquoi je ne peux pas faire quelque chose comme ça?

<TextBlock Text="{StaticResource MyPerson, Path=Name}"/> 

est-ce juste une myopie de la part du cadre? Je pense que je manque très gros ici, mais je n'arrive pas à comprendre quoi...

3) j'ai essayé D'utiliser DynamicResource, mais je suis très confus au sujet de chaque pas que j'ai pris. a) J'ai ajouté un DependencyObject avec un DependencyProperty au-dessus de ma classe de fenêtre unique dans le code (est-ce que ce DependencyObject est nécessaire?)

public class SomeText : DependencyObject
{
    public string Header
    {
        get { return (string)GetValue(HeaderProperty); }
        set { SetValue(HeaderProperty, value); }
    }
    public static readonly DependencyProperty HeaderProperty =
        DependencyProperty.Register("Header", typeof(string), typeof(SomeText), new UIPropertyMetadata(0));
}

B) en a ajouté une instance aux fenêtres.Ressources (Est-ce nécessaire avec DynamicResource? MSDN semble dire non, mais si oui, je ne peux pas comprendre comment faire la prochaine étape dans XAML)

c) j'ai essayé les deux:

Text="{Binding Source={DynamicResource HeaderText}, Path=Header}"

qui m'a donné une exception, et

Text="{DynamicResource HeaderText}"

mais je ne comprenais pas où mettre le chemin vers la propriété Header.

c'est ma 5ème tentative de tripoter avec WPF dernièrement, et chaque fois je me laisse surprendre par ces choses apparemment simples qui ne fonctionnent pas. J'ai lu deux livres et j'essaie vraiment de comprendre les articles du MSDN, mais ils ne m'aident pas du tout.

27
demandé sur OrWhen 2010-08-28 20:01:07

2 réponses

tout D'abord, un commentaire général:

WPF est difficile à apprendre. Il est difficile d'apprendre parce qu'il ya plusieurs concepts fondamentalement nouveaux que vous devez obtenir votre tête autour en même temps. La lutte que vous avez en ce moment est que vous essayez d'apprendre au moins trois choses différentes à la fois:

  • comment le XamlReader (et particulièrement les extensions de markup) désérialise XAML en objets.
  • Comment FrameworkElement les dictionnaires de ressources de travail.
  • Comment la liaison de données fonctionne.

quelque chose comme ça:

<TextBox Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/>

utilise (au moins) trois technologies très différentes en même temps. Ces technologies sont toutes conçues pour être aussi flexibles que possible, ce qui les rend seulement plus confus pour le débutant. L'idée qu'une source de liaison peut être n'importe quoi: c'est dur à saisir. L'idée qu'une extension de markup est un format spécial de sérialisation qui supporte la récursion: assez simple pour comprendre en principe, mais un peu déconcertant quand vous commencez à travailler avec des exemples du monde réel. L'idée qu'un dictionnaire de ressources peut contenir à peu près n'importe quoi, et que l'algorithme de recherche de ressources rend essentiellement les ressources héréditaires: encore une fois, assez simple dans le concept, mais facile de perdre le fil de quand vous essayez de comprendre la liaison de données et XAML dans le même temps.

c'est frustrant, parce que quelque chose qui est conceptuellement simple -" je veux lier ce contrôle à une propriété d'un objet que j'ai créé " - exige que vous comprenez un grand nombre de choses avant de pouvoir réellement l'exprimer dans XAML.

la seule solution est d'être patient, et de s'assurer que vous comprenez les choses au niveau le plus bas possible. Quand vous voyez cela:

{StaticResource MyPerson}

vous devriez être capable de penser, "cela va invoquer le gestionnaire d'extension de markup StaticResource , qui récupère un objet d'un dictionnaire de ressources en utilisant la touche MyPerson quand le XAML est désérialisé.

c'est extrêmement difficile au début. Je développe des logiciels de façon professionnelle depuis 35 ans, et J'ai constaté que WPF est la plateforme technologique la plus stimulante que j'ai jamais apprise avec une marge considérable. Mais tout ça est difficile à apprendre parce que c'est incroyablement fonctionnel et flexible. Et le résultat de l'apprentissage est énorme.

pour répondre à quelques questions que karmicpuppet n'a pas:

D'après mon expérience en MFC [ressources] étaient des icônes, des chaînes, etc.

ça n'a pas changé. Vous pouvez toujours créer des fichiers de ressources dans WPF et les charger dans des objets à l'exécution. Il existe de nombreuses façons de le faire - vous pouvez créer des ressources l'éditeur de ressources et les charger via l'objet Properties.Resources , vous pouvez ajouter des fichiers image (par exemple) au projet, les faire compiler en tant que ressources, et les charger en utilisant leur URI, et il y a beaucoup d'autres moyens que je ne connais pas.

les ressources disponibles pour FrameworkElement s via leurs dictionnaires de ressources sont une chose différente. Eh bien, en quelque sorte. Voici un exemple:

<Window.Resources>
   <Image x:Key="MyImage" Source="images/myimage.png"/>
</Window.Resources>

cela crée un objet Image et ajoute il au Window 's resource dictionary avec une clé de MyImage vous pouvez alors faire référence à cet objet via l'extension StaticResource markup dans XAML, ou la méthode FindResource dans le code.

paramétrant l'attribut Source sur l'élément Image dans XAML aussi rend le XamlReader utiliser le ResourceManager pour lire les données d'image des ressources compilées du projet à l'exécution quand il crée l'objet Image .

dans la pratique, c'est loin d'être aussi confus que lorsque vous apprenez WPF. Je n'obtiens jamais les ressources qui ResourceManager charge et les ressources stockées dans les dictionnaires de ressources mélangés.

et quand exactement cet objet créé ?

tout objet défini par un élément XAML est créé lorsque XamlReader lit l'élément. Ainsi:

<Window.Resources>
   <local:Person x:Key="MyPerson"/>
</Window.Resources>

instancie une nouvelle Person l'objet et l'ajoute à la Window dictionnaire de ressources avec une touche de MyPerson . C'est exactement l'équivalent de faire cela dans le Window 's code-behind:

AddResource("MyPerson", new Person());

alors pourquoi ne pas le faire en code-derrière? Deux raisons:

d'Abord, c'est cohérent. Si vous définissez toutes vos ressources dans XAML, vous n'avez qu'à regarder dans les fichiers XAML pour trouver ce que sont vos ressources. Si vous les définissez à la fois dans XAML et code-behind, vous devez chercher à deux endroits.

Deuxièmement, L'IDE connaît les ressources que vous définissez dans XAML. Si vous tapez

<TextBox Text="{Binding {StaticResource MyPerson}, Path=Name}"/>

dans votre XAML, L'IDE vous indiquera si vous n'avez pas défini, quelque part dans la hiérarchie des dictionnaires de ressources, une ressource dont la clé est MyPerson . Mais il ne sait pas au sujet des ressources que vous avez ajoutées dans le code, et donc même si la ressource peut en fait être détectable à l'exécution, L'IDE le signalera comme un problème.

38
répondu Robert Rossney 2010-08-29 20:59:15

pensez-y de cette façon: tous les cadres (fenêtres, boutons, autres contrôles, etc), ainsi que l'objet D'Application, contiennent un dictionnaire de ressources. Chaque fois que vous définissez une ressource dans XAML comme indiqué ici:

<Window>
  <Window.Resources>
    <SolidColorBrush x:Key="myBrush" Color="Red"/>
    <DataTemplate x:Key"myTemplate">
      <!--Template definition here -->
    </DataTemplate>
  </Window.Resources>
</Window>

c'est comme faire quelque chose comme ça en code:

class Window
{
  void Window()
  {
    this.Resources.Add("myBrush", new SolidColorBrush(Brushes.Red));
    this.Resources.Add("myTemplate", new DataTemplate());
  }
}

vous pouvez mettre toutes sortes d'objets comme ressources. Tout ce que vous souhaitez réutiliser dans votre application, vous pouvez le Définir comme Ressources.

Maintenant, lorsque vous utilisez un "{StaticResource}" comme suit:

<Button Background="{StaticResource myBrush}"/>

c'est comme dire à WPF de chercher la ressource" myBrush " correspondante et de l'appliquer à la propriété Background. Ce qui se passera, C'est que WPF va d'abord chercher la ressource dans le dictionnaire de ressources du bouton, et si elle n'est pas trouvée va chercher son parent, puis le parent de son parent, et ainsi de suite jusqu'aux ressources de l'application.

le "static" dans " StaticResource "le distingue simplement de l'autre type de recherche de ressources appelé"DynamicResource". La différence entre les deux est répondu dans ce lien .

appliqué à la reliure, il fonctionne également de la même manière. Par exemple, vous avez la ressource suivante dans votre XAML:

<local:Person x:Key="MyPerson" Name="Title"/>

et utilisé comme:

<TextBlock Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/>

dans ce cas, ce qui va se passer est quelque chose comme ceci:

Binding b = new Binding();
b.Source = FindResource("MyPerson");
b.Path = "Name";
[TextBlock].SetBinding(TextBlock.TextProperty, b);

encore une fois, le markup" {StaticResource} " dans le XAML dit à WPF de rechercher la ressource correspondante et de la définir comme la valeur de la propriété A. Dans ce cas, la propriété est la propriété "Source" de Binding.

C'est l'essentiel. J'espère que vous trouverez cela utile

14
répondu ASanch 2017-05-23 10:30:50