2015-10-12 4 views
3

J'ai une application C# WPF 4.51. Pour autant que je sache, vous ne pouvez pas lier à une propriété appartenant à un objet qui est l'enfant d'un contrôle WPF WindowsFormsHost. (Si je me trompe dans cette hypothèse s'il vous plaît me montrer comment faire):Solution de contournement pour incapacité à lier une propriété appartenant à un objet WindowsFormsHost Child dans l'application C#/XAML?

Bind with WindowsFormsHost

Dans mon cas, j'ai une page qui contient un contrôle WindowsFormsHost dont enfant objet est un ScintillaNET contrôle éditeur:

https://github.com/jacobslusser/ScintillaNET

<WindowsFormsHost x:Name="wfhScintillaTest" 
         Width="625" 
         Height="489" 
         Margin="206,98,0,0" 
         HorizontalAlignment="Left" 
         VerticalAlignment="Top"> 
     <WindowsFormsHost.Child> 
      <sci:Scintilla x:Name="scintillaCtl" /> 
     </WindowsFormsHost.Child> 
    </WindowsFormsHost> 

Le contrôle des enfants fonctionne et affiche bien. Si elle était un contrôle WPF normale je lier le Texte propriété du contrôle de l'éditeur Scintilla à une chaîne propriété dans mon ViewModel, de sorte que tout ce que je devais faire pour mettre à jour le contenu du Scintilla le contrôle de l'éditeur est mis à jour que chaîne propriété.

Mais comme je ne peux pas me lier à une propriété appartenant à un objet enfant WindowsFormsHost, je suis à la recherche d'une stratégie/solution qui ne soit pas complètement maladroite ou kludgy. Est-ce que quelqu'un a déjà fait face à ce scénario et a une stratégie raisonnable qui résout mon problème de liaison/mise à jour?

+0

Comment la propriété de contrôle de WinForm a-t-elle été définie? Peut-être que les ensembles qui peuvent l'exposer dans votre machine virtuelle? – MickyD

Répondre

6

Une approche simple ici est que vous pouvez créer une classe dédiée pour contenir uniquement des propriétés jointes correspondant aux propriétés de votre contrôle winforms. Dans ce cas, je choisis simplement Text comme exemple. Avec cette approche, vous pouvez toujours définir Binding normalement, mais les propriétés attachées seront utilisés sur le WindowsFormsHost:

public static class WindowsFormsHostMap 
{ 
    public static readonly DependencyProperty TextProperty 
     = DependencyProperty.RegisterAttached("Text", typeof(string), typeof(WindowsFormsHostMap), new PropertyMetadata(propertyChanged)); 
    public static string GetText(WindowsFormsHost o) 
    { 
     return (string)o.GetValue(TextProperty); 
    } 
    public static void SetText(WindowsFormsHost o, string value) 
    { 
     o.SetValue(TextProperty, value); 
    } 
    static void propertyChanged(object sender, DependencyPropertyChangedEventArgs e) 
    { 
     var t = (sender as WindowsFormsHost).Child as Scintilla; 
     if(t != null) t.Text = Convert.ToString(e.NewValue); 
    } 
} 

Utilisation en XAML:

<WindowsFormsHost x:Name="wfhScintillaTest" 
        Width="625" 
        Height="489" 
        Margin="206,98,0,0" 
        HorizontalAlignment="Left" 
        VerticalAlignment="Top" 
        local:WindowsFormsHostMap.Text="{Binding yourTextProp}" 
    > 
    <WindowsFormsHost.Child> 
     <sci:Scintilla x:Name="scintillaCtl"/> 
    </WindowsFormsHost.Child> 
</WindowsFormsHost> 

Le Child devrait bien sûr être Scintilla, sinon vous devez modifier le code pour le WindowsFormsHostMap.De toute façon, c'est juste pour montrer l'idée, vous pouvez toujours la modifier pour l'améliorer.

Notez que le code ci-dessus ne fonctionne que pour la liaison 1 voie (du modèle de vue au contrôle de vos winforms). Si vous voulez l'inverse, vous devez enregistrer un gestionnaire d'événements pour le contrôle et mettre à jour la valeur à la propriété jointe dans ce gestionnaire. C'est assez compliqué de cette façon.

+0

Merci. Pourquoi utiliser une classe de conteneur statique et une proopery sous-jacente au lieu d'une classe de conteneur et d'une propriété normales? (exemple: http://stackoverflow.com/questions/11226843/data-binding-in-wpf-user-controls). Dans ce post SO, la déclaration DependencyProperty est statique, mais la propriété qu'elle expose et la classe hôte ne l'est pas. Je me demande pourquoi la différence entre les deux approches? –

+1

@RobertOschler pour UserControl et vous avez accès à sa classe, vous pouvez ajouter une propriété d'instance (un wrapper de dependencyProperty). Mais ici le 'WindowsFormsHost' n'est pas votre classe, donc l'utilisation de la propriété jointe est un moyen pratique. Si vous le souhaitez, vous pouvez le sous-classer et y déclarer votre propriété, et bien sûr utiliser cette classe au lieu de 'WindowsFormsHost'. –

1

Vous pouvez uniquement obtenir une liaison très, très limitée avec un contrôle Windows Forms car ils ne recevront pas de notifications de mise à jour et devront être interrogés explicitement pour obtenir les résultats via une méthode personnalisée RefreshValues() ou quelque chose qui interroge chaque pièce de données.

Mais si tout ce que vous avez besoin est d'accéder au contrôle des enfants, vous devriez faire la liaison dans le code:

(WFH.Child as MyWinFormsControl).Text 

Si vous avez l'intention de faire beaucoup de la liaison, il pourrait être plus facile de créer une enveloppe WPF objet (UserControl peut-être) qui possède toutes les propriétés dont vous avez besoin en tant que DependencyProperties et le code sous-jacent que chaque propriété interrogerait manuellement le contrôle WinForms comme s'il s'agissait du champ de sauvegarde de la propriété. C'est un peu compliqué au début, mais plus facile que d'interroger manuellement chaque propriété.

+1

_ "Liaison très limitée avec un contrôle Windows Forms en tant que liaison ne recevra pas les notifications de mise à jour" _ - Êtes-vous sûr? 'INotifyPropertyChanged' est antérieur à WPF. – MickyD

+0

Je pourrais me tromper (ce qui serait génial dans ce cas :) - mais je parle principalement d'expérience personnelle. Bien que les notifications de propriété existent, elles n'étaient pas mises à jour correctement, d'où le wrapper que nous avons créé. –