28

मैं इस पर एक पाठ बॉक्स के साथ एक कस्टम उपयोगकर्ता नियंत्रण है और मैं कस्टम नियंत्रण से बाहर (पाठ बॉक्स में पाठ का) आधार रेखा को बेनकाब करने के snapline चाहते हैं। मुझे पता है कि आप एक डिज़ाइनर (कंट्रोलडिज़ाइनर से विरासत में प्राप्त) बनाते हैं और स्नैपलाइन तक पहुंच प्राप्त करने के लिए स्नैपलाइन को ओवरराइड करते हैं, लेकिन मैं सोच रहा हूं कि मेरे कस्टम उपयोगकर्ता नियंत्रण द्वारा मेरे द्वारा उपयोग किए गए नियंत्रण की टेक्स्ट बेसलाइन कैसे प्राप्त करें।आधारभूत snaplines को नियंत्रित करता है

उत्तर

24

मैं सिर्फ एक समान की जरूरत थी, और मैं इसे इस तरह हल:

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; 
    } 
} 

इस तरह यह वास्तव में subcontrol के लिए एक अस्थायी उप डिजाइनर बनाने है क्रम में पता लगाने के लिए जहां "असली" आधारभूत snapline है।

यह परीक्षण में उचित रूप से प्रदर्शन करने वाला प्रतीत होता है, लेकिन अगर परफ चिंता का विषय बन जाता है (और यदि आंतरिक टेक्स्टबॉक्स नहीं चलता है) तो इस कोड का अधिकांश प्रारंभिक विधि में निकाला जा सकता है।

यह भी मान लिया है कि पाठ बॉक्स UserControl का एक सीधा बच्चा है। यदि रास्ते में अन्य लेआउट-प्रभावित नियंत्रण हैं तो ऑफसेट गणना थोड़ा और जटिल हो जाती है।

+1

बहुत बढ़िया। ऐसा करने के लिए हमें इसकी आवश्यकता थी। धन्यवाद! – Mike

+3

हमारे पास कई नियंत्रण हैं जिनके लिए हमें काम करने की आवश्यकता है ताकि हम इसे नियंत्रण के लिए एक सामान्य डिजाइनर में फैक्टरिंग कर सकें कि हमने एक "अपरिवर्तनीय" इंटरफ़ेस को कार्यान्वित किया है जिसे हम स्पष्ट रूप से कार्यान्वित करते हैं और नियंत्रणों का खुलासा करते हैं। इस तरह तर्क अभी भी डिजाइनर में encapsulated है लेकिन सामान्यीकृत। – Mike

2

आप सही रास्ते पर हैं। आप इस तरह से अपनी designr में SnapLines संपत्ति को ओवरराइड और कुछ करने के लिए की आवश्यकता होगी:

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 

इस उदाहरण में usercontrol एक पाठ बॉक्स शामिल हैं। कोड एक नई स्नैपलाइन जोड़ता है जो टेक्स्टबॉक्स के लिए आधार रेखा का प्रतिनिधित्व करता है। ऑफसेट की सही गणना करना महत्वपूर्ण बात है।

37

Miral के जवाब के लिए एक अद्यतन के रूप में .. यहाँ, "लापता चरण" के कुछ नए किसी को उस ऐसा करने के तरीके के लिए देख रहा है के लिए कर रहे हैं। :) उपरोक्त सी # कोड लगभग 'ड्रॉप-इन' तैयार है, जिसमें उपयोगकर्ता नियंत्रण को संदर्भित करने के लिए कुछ मानों को बदलने के अपवाद के साथ संशोधित किया जाएगा।

संभव संदर्भ आवश्यक:
System.Design (@robyaw)

usings की जरूरत:

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

अपने UserControl आप निम्नलिखित गुण की जरूरत पर:

[Designer(typeof(MyCustomDesigner))] 

फिर आप की जरूरत एक "डिजाइनर" वर्ग जिसमें स्नैपलाइन ओवरराइड होगा:

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; 
} 

    } 
    } 
} 
+6

एक बड़ा अप वोट (इच्छा मैं और अधिक दे सकता हूं) क्योंकि आप उल्लेख करने के लिए परेशान हैं, आपको अपने उपयोगकर्ता नियंत्रण के अंदर ControlDesigner क्लास डालना होगा और डिजाइनर विशेषता के साथ अपने उपयोगकर्ता नियंत्रण कक्षा को सजाने की आवश्यकता है जो ControlDesigner क्लास को निर्देशित करता है। एक बार जब आप इसे देखते हैं तो सभी समझ में आता है, लेकिन पहले नहीं। चीयर्स। –

+0

स्टुअर्ट - मुझे एक ही समस्या थी, इसलिए मैंने इस प्रश्न में जोड़ा। मुझे खुशी है कि अतिरिक्त जानकारी आपकी मदद करने में सक्षम थी! –

+0

मैं इसे आजमा रहा हूं लेकिन वीएस2012 नियंत्रण डिज़ाइनर को पहचान नहीं पा रहा है, मैं Winforms का उपयोग कर रहा हूं, और .NET 4.5 ive ने ऐसा कुछ नहीं किया है, इसलिए मुझे कुछ गलत करने का अनुमान है लेकिन क्या पता नहीं लगा सकता? – f1wade

6

वीबी.Net संस्करण:
नोट: आपको txtDescription को टेक्स्टबॉक्स या किसी अन्य आंतरिक नियंत्रण नाम में बदलना है जिसका आप उपयोग करते हैं। और ctlUserControl अपने 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 
6

मदद के लिए उन सभी को धन्यवाद। निगलना मुश्किल था। प्रत्येक उपयोगकर्ता नियंत्रण में एक निजी उप-वर्ग होने का विचार बहुत ही सुखद नहीं था।

मैं इस बेस क्लास के साथ मदद करने के लिए आया था ..इस पोस्ट करने के लिए फिर से

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

    ... 

} 

धन्यवाद:

[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; 
      } 
     } 
    } 
} 

इसके बाद, इस आधार से अपने UserControl निकाले जाते हैं।

+0

यह समस्या के लिए एक सुंदर और सामान्य समाधान है। धन्यवाद। – abrahala