Question

J'ai un contrôle utilisateur personnalisé avec une zone de texte dessus et j'aimerais exposer la ligne de base (du texte dans la zone de texte) le snapline en dehors du contrôle personnalisé. Je sais que vous créez un concepteur (hérité de ControlDesigner) et substituez SnapLines pour accéder aux lignes de scénario, mais je me demande comment obtenir la ligne de base du texte d'un contrôle que j'ai exposé par mon contrôle utilisateur personnalisé.

Était-ce utile?

La solution

Je viens d'avoir un besoin similaire, et je l'ai résolu comme suit:

 public override IList SnapLines
{
    get
    {
        IList snapLines = base.SnapLines;

        MyControl control = Control as MyControl;
        if (control == null) { return snapLines; }

        IDesigner designer = TypeDescriptor.CreateDesigner(
            control.textBoxValue, typeof(IDesigner));
        if (designer == null) { return snapLines; }
        designer.Initialize(control.textBoxValue);

        using (designer)
        {
            ControlDesigner boxDesigner = designer as ControlDesigner;
            if (boxDesigner == null) { return snapLines; }

            foreach (SnapLine line in boxDesigner.SnapLines)
            {
                if (line.SnapLineType == SnapLineType.Baseline)
                {
                    snapLines.Add(new SnapLine(SnapLineType.Baseline,
                        line.Offset + control.textBoxValue.Top,
                        line.Filter, line.Priority));
                    break;
                }
            }
        }

        return snapLines;
    }
}

Ainsi, il crée un sous-concepteur temporaire pour le sous-contrôle afin de déterminer où se trouve le "réel". La ligne de base est.

Cela semblait raisonnablement performant lors des tests, mais si perf devient une préoccupation (et si la zone de texte interne ne bouge pas), la plupart de ce code peut être extrait dans la méthode Initialize.

Cela suppose également que la zone de texte est un enfant direct de UserControl. S'il existe d'autres commandes affectant la présentation, le calcul du décalage devient un peu plus compliqué.

Autres conseils

Comme mise à jour de la réponse du Miral, voici quelques "étapes manquantes" pour une nouvelle personne qui cherche comment faire cela. :) Le code C # ci-dessus est presque prêt à l'emploi, à l'exception de la modification de quelques valeurs pour faire référence à UserControl qui sera modifié.

Références possibles nécessaires:
    System.Design (@robyaw)

Utilisation requise:

using System.Windows.Forms.Design;
using System.Windows.Forms.Design.Behavior;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;

Sur votre UserControl, vous avez besoin de l'attribut suivant:

[Designer(typeof(MyCustomDesigner))]

Ensuite, vous avez besoin d’un "concepteur". classe qui aura le remplacement SnapLines:

private class MyCustomerDesigner : ControlDesigner {
  public override IList SnapLines {
    get {
     /* Code from above */
    IList snapLines = base.SnapLines;

    // *** This will need to be modified to match your user control
    MyControl control = Control as MyControl;
    if (control == null) { return snapLines; }

    // *** This will need to be modified to match the item in your user control
    // This is the control in your UC that you want SnapLines for the entire UC
    IDesigner designer = TypeDescriptor.CreateDesigner(
        control.textBoxValue, typeof(IDesigner));
    if (designer == null) { return snapLines; }

    // *** This will need to be modified to match the item in your user control
    designer.Initialize(control.textBoxValue);

    using (designer)
    {
        ControlDesigner boxDesigner = designer as ControlDesigner;
        if (boxDesigner == null) { return snapLines; }

        foreach (SnapLine line in boxDesigner.SnapLines)
        {
            if (line.SnapLineType == SnapLineType.Baseline)
            {
                // *** This will need to be modified to match the item in your user control
                snapLines.Add(new SnapLine(SnapLineType.Baseline,
                    line.Offset + control.textBoxValue.Top,
                    line.Filter, line.Priority));
                break;
            }
        }
    }

    return snapLines;
}

    }
  }
}

Merci à tous ceux pour l'aide. C'était difficile à avaler. Avoir une sous-classe privée dans chaque UserControl n’était pas très agréable.

Je suis venu avec cette classe de base pour aider ..

[Designer(typeof(UserControlSnapLineDesigner))]
public class UserControlBase : UserControl
{
    protected virtual Control SnapLineControl { get { return null; } }

    private class UserControlSnapLineDesigner : ControlDesigner
    {
        public override IList SnapLines
        {
            get
            {
                IList snapLines = base.SnapLines;

                Control targetControl = (this.Control as UserControlBase).SnapLineControl;

                if (targetControl == null)
                    return snapLines;

                using (ControlDesigner controlDesigner = TypeDescriptor.CreateDesigner(targetControl,
                    typeof(IDesigner)) as ControlDesigner)
                {
                    if (controlDesigner == null)
                        return snapLines;

                    controlDesigner.Initialize(targetControl);

                    foreach (SnapLine line in controlDesigner.SnapLines)
                    {
                        if (line.SnapLineType == SnapLineType.Baseline)
                        {
                            snapLines.Add(new SnapLine(SnapLineType.Baseline, line.Offset + targetControl.Top,
                                line.Filter, line.Priority));
                            break;
                        }
                    }
                }
                return snapLines;
            }
        }
    }
}

Ensuite, dérivez votre UserControl de cette base:

public partial class MyControl : UserControlBase
{
    protected override Control SnapLineControl
    {
        get
        {
            return txtTextBox;
        }
    }

    ...

}

Merci encore d'avoir posté ce message.

Version VB.Net:
Remarque: vous devez remplacer txtDescription par la zone de texte ou un autre nom de contrôle interne que vous utilisez. et ctlUserControl à votre nom usercontrol

<Designer(GetType(ctlUserControl.MyCustomDesigner))> _
Partial Public Class ctlUserControl
   '... 
   'Your Usercontrol class specific code
   '... 
    Class MyCustomDesigner
        Inherits ControlDesigner
        Public Overloads Overrides ReadOnly Property SnapLines() As IList
            Get
                ' Code from above 

                Dim lines As IList = MyBase.SnapLines

                ' *** This will need to be modified to match your user control
                Dim control__1 As ctlUserControl = TryCast(Me.Control, ctlUserControl)
                If control__1 Is Nothing Then Return lines

                ' *** This will need to be modified to match the item in your user control
                ' This is the control in your UC that you want SnapLines for the entire UC
                Dim designer As IDesigner = TypeDescriptor.CreateDesigner(control__1.txtDescription, GetType(IDesigner))
                If designer Is Nothing Then
                    Return lines
                End If

                ' *** This will need to be modified to match the item in your user control
                designer.Initialize(control__1.txtDescription)

                Using designer
                    Dim boxDesigner As ControlDesigner = TryCast(designer, ControlDesigner)
                    If boxDesigner Is Nothing Then
                        Return lines
                    End If

                    For Each line As SnapLine In boxDesigner.SnapLines
                        If line.SnapLineType = SnapLineType.Baseline Then
                            ' *** This will need to be modified to match the item in your user control
                            lines.Add(New SnapLine(SnapLineType.Baseline, line.Offset + control__1.txtDescription.Top, line.Filter, line.Priority))
                            Exit For
                        End If
                    Next
                End Using

                Return lines
            End Get
        End Property
    End Class

End Class

Vous êtes sur la bonne voie. Vous devrez remplacer la propriété SnapLines dans votre concepteur et faire quelque chose comme ceci:

Public Overrides ReadOnly Property SnapLines() As System.Collections.IList
    Get
        Dim snapLinesList As ArrayList = TryCast(MyBase.SnapLines, ArrayList)

        Dim offset As Integer
        Dim ctrl As MyControl = TryCast(Me.Control, MyControl)
        If ctrl IsNot Nothing AndAlso ctrl.TextBox1 IsNot Nothing Then
            offset = ctrl.TextBox1.Bottom - 5
        End If

        snapLinesList.Add(New SnapLine(SnapLineType.Baseline, offset, SnapLinePriority.Medium))

        Return snapLinesList

    End Get
End Property

Dans cet exemple, le contrôle utilisateur contient une zone de texte. Le code ajoute une nouvelle ligne de jeu qui représente la référence pour la zone de texte. L'important est de calculer le décalage correctement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top