45 votes

Définition d'une propriété personnalisée dans une page WPF / Silverlight

Cela sonne comme il devrait être simple. J'ai un Page déclarée dans le code XAML de la manière normale (c'est à dire avec "Ajouter un nouvel élément...") et il a une propriété personnalisée. J'aimerais définir cette propriété dans le code XAML de la page.

En essayant de le faire de la même manière que je l'avais mis toute autre propriété ne fonctionne pas, pour des raisons que je comprends, mais ne savent pas comment travailler en rond. Seulement alors, nous avons quelque chose de concret pour en parler, voici quelques (invalides) XAML. J'ai réduit tout vers le bas autant que possible - à l'origine, il y avait des attributs tels que le concepteur de la taille, mais je crois que ceux qui ne sont pas pertinents pour ce que je suis en train de faire.

<Page x:Class="WpfSandbox.TestPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      MyProperty="MyPropertyValue">
</Page>

et le code-behind:

using System.Windows.Controls;

namespace WpfSandbox {
  public partial class TestPage : Page {
    public TestPage() {
      InitializeComponent();
    }

    public string MyProperty { get; set; }
  }
}

Message d'erreur:

Erreur 1 La propriété 'MyProperty" n'existe pas dans l'espace de noms XML 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'. La Ligne 4 En Position 7.

Maintenant je sais pourquoi c'est un échec: l'élément est de type Page, et Page n'ont pas une propriété appelée MyProperty. C'est seulement déclaré en TestPage... ce qui est spécifié par l' x:Class d'attribut, mais pas par l'élément lui-même. Pour autant que je suis conscient que, cette configuration est requise par le code XAML modèle de traitement (c'est à dire l'intégration de Visual Studio, etc).

Je pense que je pourrais gérer cela avec une dépendance de la propriété, mais qui se sent un peu comme exagéré. J'ai pu également utiliser une propriété existante (par exemple, DataContext), puis de copier la valeur dans la propriété personnalisée dans le code plus tard, mais qui serait assez laid.

Le dessus est un WPF exemple, mais je soupçonne les mêmes réponses seront d'application en Silverlight. Je suis intéressé dans les deux - si vous postez une réponse qui vous savez travailler dans l'un mais pas l'autre, je lui en serais reconnaissant si vous m'indiquent que dans la réponse :)

Je suis en train de préparer pour le coup moi-même quand quelqu'un poste un absolument solution triviale...

33voto

abhishek Points 1746

Vous pouvez travailler avec une propriété normale sans propriété de dépendance si vous créez une classe de base pour votre page.

  public class BaseWindow : Window
 {
   public string MyProperty { get; set; }
 }

<local:BaseWindow x:Class="BaseWindowSample.Window1" x:Name="winImp"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:BaseWindowSample" 
    MyProperty="myproperty value"
    Title="Window1" Height="300" Width="300">

</local:BaseWindow>
 

Et cela fonctionne même si MyProperty n'est pas une dépendance ou une pièce jointe.

6voto

Filip Ekberg Points 22189

Vous auriez besoin d'en faire un des biens saisissables que Pavel a noté, alors vous pouvez écrire quelque chose comme ceci

<Page x:Class="JonSkeetTest.SkeetPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:JonSkeetTest="clr-namespace:JonSkeetTest" mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
       JonSkeetTest:SkeetPage.MyProperty="testar"
    Title="SkeetPage">
    <Grid>

    </Grid>
</Page>

Cependant, avec seulement ce code derrière:

Vous obtiendrez cette erreur à la place:

Les biens saisissables 'MyProperty' n'a pas été trouvé dans le "type de SkeetPage'.

La propriété attachée 'SkeetPage.MyProperty " n'est pas défini sur 'Page' ou une de ses classes de base.


Modifier

Malheureusement, vous devez utiliser les Propriétés de Dépendance, elle est un exemple de travail

Page

<Page x:Class="JonSkeetTest.SkeetPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:JonSkeetTest="clr-namespace:JonSkeetTest" mc:Ignorable="d" 
      JonSkeetTest:SkeetPage.MyProperty="Testing.."
      d:DesignHeight="300" d:DesignWidth="300"
    Title="SkeetPage">

    <Grid>
        <Button Click="ButtonTest_Pressed"></Button>
    </Grid>
</Page>

Le Code-behind

using System.Windows;
using System.Windows.Controls;

namespace JonSkeetTest
{
    public partial class SkeetPage
    {
        public SkeetPage()
        {
            InitializeComponent();
        }

        public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register(
          "MyProperty",
          typeof(string),
          typeof(Page),
          new FrameworkPropertyMetadata(null,
              FrameworkPropertyMetadataOptions.AffectsRender
          )
        );

        public static void SetMyProperty(UIElement element, string value)
        {
            element.SetValue(MyPropertyProperty, value);
        }
        public static string GetMyProperty(UIElement element)
        {
            return element.GetValue(MyPropertyProperty).ToString();
        }

        public string MyProperty
        {
            get { return GetValue(MyPropertyProperty).ToString(); }
            set { SetValue(MyPropertyProperty, value); }
        }

        private void ButtonTest_Pressed(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(MyProperty);
        }
    }
}

Si vous appuyez sur le bouton, vous verrez "Essai..." dans une MessageBox.

3voto

Håvard S Points 11152

Vous pouvez déclarer votre <Page> élément à un <TestPage> élément à la place:

<YourApp:TestPage 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  xmlns:YourApp="clr-namespace:YourApp"
  MyProperty="Hello">
</YourApp:TestPage>

Que ferait l'affaire, mais vous perdez InitializeComponent() et le standard concepteur de trucs. Design de mode semble fonctionner parfaitement, si, mais je n'ai pas testé cette.

Mise à JOUR: il compile et s'exécute, mais n'a pas réellement MyProperty. Vous perdez également la capacité de lier les gestionnaires d'événements dans le XAML (bien qu'il puisse être un moyen de restaurer ce que je ne suis pas au courant de).

Mise à JOUR 2: exemple de Travail de @Fredrik Mork qui définit la propriété, mais ne prend pas en charge la liaison de gestionnaires d'événements dans le code XAML:

Code derrière:

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        protected override void OnActivated(EventArgs e)
        {
            this.Title = MyProperty;
        }      

        public string MyProperty { get; set; }
    }
}

XAML:

<WpfApplication1:MainWindow
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:WpfApplication1="clr-namespace:WpfApplication1" 
    Title="MainWindow" 
    Height="350" 
    Width="525"
    MyProperty="My Property Value"> 
</WpfApplication1:MainWindow>

2voto

Alf Kåre Lefdal Points 167

Votre XAML est équivalente à la suivante:

<Page x:Class="SkeetProblem.TestPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.MyProperty>MyPropertyValue</Page.MyProperty> 
</Page>

C'est évidemment illégal. Le XAML fichier a été chargé par le statique LoadComponent méthode de la classe d'Application, et la référence dit:

Charge un fichier XAML qui est situé à l'identificateur de ressource uniforme (URI) et la convertit en une instance de l'objet qui est spécifié par l'élément racine du fichier XAML.

Cela signifie que vous ne pouvez définir des propriétés pour le type spécifié par l'élément racine. Si vous avez besoin de sous-classe et de la Page de préciser que la sous-classe en tant qu'élément racine de vous XAML.

1voto

Arcturus Points 14366

Ma suggestion serait un DependencyProperty avec une valeur par défaut:

    public int MyProperty
    {
        get { return (int)GetValue(MyPropertyProperty); }
        set { SetValue(MyPropertyProperty, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty =
        DependencyProperty.Register("MyProperty", typeof(int), typeof(MyClass), 
               new PropertyMetadata(1337)); //<-- Default goes here

Voir les propriétés des contrôles comme quelque chose de vous exposer au monde extérieur à utiliser.

Si vous souhaitez utiliser votre propre propriété, que vous pouvez utiliser ElementName ou RelativeSource Fixations.

À propos de l'overkill chose, DependencyProperties vont main dans la main avec l' DependencyObjects ;)

Aucune autre XAML nécessaire, la valeur par défaut dans l' PropertyMetadata fera le reste.

Si vous voulez vraiment vous mettre dans le code XAML, rendez-vous pour la classe de base de la solution, ou les dieux ne plaise, introduire un des biens saisissables, qui peut être utilisé sur n'importe quel autre contrôle ainsi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X