28

Tôi có một điều khiển người dùng tùy chỉnh với một hộp văn bản trên đó và tôi muốn phơi bày đường cơ sở (của văn bản trong hộp văn bản) bên ngoài điều khiển tùy chỉnh. Tôi biết rằng bạn tạo một nhà thiết kế (kế thừa từ ControlDesigner) và ghi đè SnapLines để truy cập vào các snapline, nhưng tôi tự hỏi làm thế nào để có được đường cơ sở của một điều khiển mà tôi đã kiểm soát người dùng tùy chỉnh của mình.Đường cơ sở trong các điều khiển Winforms tùy chỉnh

Trả lời

24

Tôi chỉ có một nhu cầu tương tự, và tôi giải quyết nó như thế này:

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

Bằng cách này nó thực sự tạo ra một sub-nhà thiết kế tạm thời cho subcontrol để tìm ra nơi mà "thật" snapline cơ bản Là.

Điều này có vẻ hợp lý trong thử nghiệm, nhưng nếu perf trở thành mối quan tâm (và nếu hộp văn bản bên trong không di chuyển) thì phần lớn mã này có thể được trích xuất theo phương pháp khởi tạo.

Điều này cũng giả định rằng hộp văn bản là con trực tiếp của UserControl. Nếu có các điều khiển bố cục ảnh hưởng khác theo cách thì tính toán bù đắp sẽ trở nên phức tạp hơn một chút.

+1

Tuyệt vời. Điều đó đã làm những gì chúng tôi cần nó để làm. Cảm ơn! – Mike

+3

Chúng tôi có một số điều khiển mà chúng tôi cần để làm việc vì vậy chúng tôi đã kết thúc việc này thành một nhà thiết kế chung cho các điều khiển mà chúng tôi đã triển khai giao diện "Không thể phát hiện" mà chúng tôi triển khai và hiển thị một cách rõ ràng. Bằng cách này, logic vẫn được đóng gói trong nhà thiết kế nhưng được tổng quát hóa. – Mike

2

Bạn đang đi đúng hướng. Bạn sẽ cần phải ghi đè thuộc tính SnapLines trong designr của bạn và làm một cái gì đó như thế này:

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 

Trong ví dụ này, usercontrol chứa một hộp văn bản. Mã này bổ sung thêm một snapline mới đại diện cho đường cơ sở cho hộp văn bản. Điều quan trọng là tính toán độ lệch chính xác.

37

Là bản cập nhật cho câu trả lời của Miral .. dưới đây là một vài trong số "các bước bị thiếu", đối với người mới đang tìm cách thực hiện việc này. :) Mã C# ở trên gần như là 'drop-in' đã sẵn sàng, ngoại trừ việc thay đổi một vài giá trị để tham chiếu UserControl sẽ được sửa đổi.

Tài liệu tham khảo có thể cần thiết:
System.Design (@robyaw)

usings cần thiết:

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

On UserControl của bạn, bạn cần thuộc tính sau:

[Designer(typeof(MyCustomDesigner))] 

Sau đó, bạn cần một lớp "nhà thiết kế" sẽ ghi đè lên 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; 
} 

    } 
    } 
} 
+6

Một cuộc bỏ phiếu lớn lên (ước gì tôi có thể đưa ra nhiều hơn) bởi vì bạn đã đề cập đến, bạn cần phải đặt lớp ControlDesigner INSIDE UserControl của bạn VÀ trang trí lớp UserControl của bạn với thuộc tính Designer mà quy định lớp ControlDesigner. Tất cả đều có ý nghĩa khi bạn thấy điều đó, nhưng không phải trước đây. Chúc mừng. –

+0

Stuart - Tôi có cùng một vấn đề, đó là lý do tôi thêm vào câu hỏi này. Tôi rất vui vì thông tin bổ sung có thể giúp bạn! –

+0

Im cố gắng này nhưng VS2012 không nhận ra ControlDesigner, im bằng cách sử dụng winforms, và .net 4.5 ive không bao giờ làm điều này trước khi như vậy presume im làm điều gì đó sai, nhưng không thể tìm ra những gì? – f1wade

6

VB.Net Phiên bản:
Lưu ý: bạn phải thay đổi txtDescription thành Hộp văn bản hoặc tên kiểm soát nội bộ khác mà bạn sử dụng. và ctlUserControl tới số usercontrol tên

<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

Nhờ tất cả những người trợ giúp. Đây là một thứ khó nuốt. Ý nghĩ có một sub-class riêng trong mỗi UserControl không phải là rất ngon miệng.

Tôi đã tìm ra lớp cơ sở này để trợ giúp ..

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

Tiếp theo, lấy UserControl của bạn từ cơ sở này:

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

    ... 

} 

Cảm ơn một lần nữa đã gửi bài này.

+0

Đây là một giải pháp tuyệt vời và chung chung cho vấn đề này. Cảm ơn bạn. – abrahala

Các vấn đề liên quan