2017-03-22 14 views
4

最近、クラスの拡張機能と組み合わせてイベント/デリゲートの詳細を学び始めました。C#:派生クラスを1つの汎用パラメータとして渡す

私は順番に制御を動き回ることMouseDownMouseMoveイベントを使用していますSetDraggable()と呼ばれるWindowsフォームコントロールに拡張方法を、追加することによって、実際に学んだことを置くことを望んでいました。

すべてが問題なく動作しますが、特定のコントロール(私の場合はButton)にのみ適用されます。図から分かるように

namespace Form_Extensions 
{ 
    public static class Extensions 
    { 
     private static System.Windows.Forms.Button StubButton; 
     private static Point MouseDownLocation; 
     public static void SetDraggable(this System.Windows.Forms.Button b) 
     { 
      b.MouseDown += b_MouseDown; 
      b.MouseMove += b_MouseMove; 
      StubButton = b; 
     } 

     private static void b_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) 
     { 
      if (e.Button == System.Windows.Forms.MouseButtons.Left) 
      { 
       MouseDownLocation = e.Location; 
      } 
     } 

     static void b_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) 
     { 
      if (e.Button == System.Windows.Forms.MouseButtons.Left) 
      { 
       StubButton.Left = e.X + StubButton.Left - MouseDownLocation.X; 
       StubButton.Top = e.Y + StubButton.Top - MouseDownLocation.Y; 
      } 
     } 

    } 
} 

、私はマウスイベントを呼び出すために具体的な制御を必要とする - 私はクラスSystem.Windows.Formsからこれらのイベントにアクセスすることはできません。

私の質問は残っています。プログラマがに総ての派生クラスを引数として渡すことを許可するコンセプトはありますか。私は基本的にすべての単一のコントロールの下のコードを貼り付けるのを避けようとしており、System.Windows.Formsから派生したすべてのクラスに対してそれを一般化したいと思います。

私が知る限り、そのアイデアの主な欠陥は、私がと書いていることです。を援助します。派生クラスはすべて私が必要とするイベントを持ちます。しかし、同様のことが関数の代理人の形で存在するので、私は、オブジェクトやパラメータを含む場合に誰かが体重を増やすことを望んでいました。ここでは、ジェネリック医薬品のための必要はあり

public static class Extensions 
{ 
    private static System.Windows.Forms.Control StubButton; 
    private static Point MouseDownLocation; 

    public static void SetControlDraggable(this System.Windows.Forms.Control b) 
    { 
     b.MouseDown += b_MouseDown; 
     b.MouseMove += b_MouseMove; 
     StubButton = b; 
    } 

    public static void SetDraggable<T>(this T b) 
     where T:System.Windows.Forms.Control 
    { 
     b.MouseDown += b_MouseDown; 
     b.MouseMove += b_MouseMove; 
     StubButton = b; 
    } 

    private static void b_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) 
    { 
     if (e.Button == System.Windows.Forms.MouseButtons.Left) 
     { 
      MouseDownLocation = e.Location; 
     } 
    } 

    private static void b_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) 
    { 
     if (e.Button == System.Windows.Forms.MouseButtons.Left) 
     { 
      StubButton.Left = e.X + StubButton.Left - MouseDownLocation.X; 
      StubButton.Top = e.Y + StubButton.Top - MouseDownLocation.Y; 
     } 
    } 
} 
+1

についてもっと知ります名前空間。親クラスは 'Control'であり、あなたは確かにそれを使うことができます:)ジェネリックメソッドを使うことも可能ですが、実際には必要ありません。理想的には、これらの静的フィールドを避けたい場合もあります。複数の並行ドラッグを持つことが可能であるためです。 'SetControlDraggable'メソッドのクロージャーはもっと良く機能します。または、単に 'sender'を使うと、それは本当にそれが何であるのかです。 – Luaan

答えて

6

親クラスがそれはちょうどだ、System.Windows.Formsではありません名前空間。実際の親クラスはControlであり、確かにそれを使うことができます:)ジェネリックメソッドを使うことも可能ですが、実際には必要ありません。

理想的には、これらの静的フィールドを避けたい場合もあります。複数の並行してドラッグすることが可能です。 SetControlDraggable方法での閉鎖はかなり良く動作します:

一般的な問題について
public static void SetControlDraggable(this Control control) 
{ 
    Point mouseDownLocation = Point.Empty; 

    control.MouseDown += (s, e) => 
    { 
     if (e.Button == MouseButtons.Left) mouseDownLocation = e.Location; 
    } 
    control.MouseUp += (s, e) => 
    { 
     if (e.Button == MouseButtons.Left) 
     { 
     control.Left = e.X + control.Left - mouseDownLocation.X; 
     control.Top = e.Y + control.Top - mouseDownLocation.Y; 
     } 
    } 
} 
+0

閉鎖の良いアイデアです。私は静的な点を避ける方法について考えましたが、この優雅な解決策を考え出すことができず、実際には問題ではないと考えました。もちろん、このソリューションはより安全です。 –

+0

名前空間との混乱についてご説明いただきありがとうございます。また、静的なフィールドを取り除くことによって私はさらに問題を減らしてくれてありがとう! –

1

は二つの可能性があります。 Control基本クラスをそのまま使うことができます。拡張機能はControlから派生したすべてのクラスで動作します。

public static void SetDraggable(this Control c) 
{ 
     c.MouseDown += c_MouseDown; 
     c.MouseMove += c_MouseMove; 
     control = c; 
} 

そして、あなたはこれがあなたのイベントハンドラのsender引数として渡されると、コントロールの参照を保持するために、静的メンバを必要としない:

private static void c_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) 
{ 
    Control control = (Control)sender; 
    if (e.Button == System.Windows.Forms.MouseButtons.Left) 
    { 
     control.Left = e.X + control.Left - MouseDownLocation.X; 
     controlTop = e.Y + control.Top - MouseDownLocation.Y; 
    } 
} 
3

ではありません:

1

、他の記事は、あなたが問題を解決するのに役立ちます。メソッドをジェネリックにする必要はありません。メソッドのタイプとしてControlを使用するだけで十分です。何らかの理由でジェネリックにしたい場合は、タイプがControlの派生型であることを示すwhere句を追加すれば十分です。クラス。Windowsフォームの場合

エクステンダープロバイダコンポーネント

、コントロールにそのような拡張を追加するための良い解決策は、あなたのためのデザイン時サポートをもたらす延長剤成分を作成しています。エクステンダコンポーネントを作成し、EnableDragプロパティを他のコンポーネントに追加すると、trueまたはfalseに設定してドラッグ可能にすることができます。

エクステンダプロバイダによって提供されるプロパティは、実際にエクステンダプロバイダオブジェクト自体に存在するため、変更するコンポーネントの真のプロパティではありません。しかし、設計時には、プロパティが拡張コントロールのプロパティウィンドウに表示されます。また、実行時に、エクステンダコンポーネントのgetterメソッドとsetterメソッドを呼び出すことによって、プロパティにアクセスすることはできません。

この例では、私はDraggableExtender延長剤成分を作成しました。フォームにこのコンポーネントのインスタンスをドロップすると、すべてのコントロールのデザイン時にtrueまたはfalseに設定できるEnableDrag on draggableExtender1という名前のプロパティが追加されます。その後、コントロールを実行時にtrueに設定すると、ドラッグ可能になります。

using System.Collections.Generic; 
using System.ComponentModel; 
using System.Drawing; 
using System.Windows.Forms; 
[ProvideProperty("EnableDrag", typeof(Control))] 
public class DraggableExtender : Component, IExtenderProvider 
{ 
    private Dictionary<Control, bool> EnableDragValues = 
     new Dictionary<Control, bool>(); 
    public bool CanExtend(object extendee) 
    { 
     //You can limit the type of extendee here 
     if (extendee is Control) 
      return true; 
     return false; 
    } 
    public bool GetEnableDrag(Control control) 
    { 
     if (EnableDragValues.ContainsKey(control)) 
      return EnableDragValues[control]; 
     return false; 
    } 
    public void SetEnableDrag(Control control, bool value) 
    { 
     EnableDragValues[control] = value; 
     { 
      if (value) 
      { 
       control.MouseDown += MouseDown; 
       control.MouseMove += MouseMove; 
       control.Cursor = Cursors.SizeAll; 
      } 
      else 
      { 
       control.MouseDown -= MouseDown; 
       control.MouseMove -= MouseMove; 
       control.Cursor = Cursors.Default; 
      } 
     } 
    } 

    Point p1; 
    private void MouseDown(object sender, MouseEventArgs e) 
    { 
     if (e.Button == MouseButtons.Left) 
      p1 = Cursor.Position; 
    } 
    private void MouseMove(object sender, MouseEventArgs e) 
    { 
     if (e.Button == MouseButtons.Left) 
     { 
      var control = (Control)sender; 
      var p = control.Location; 
      p.Offset(Cursor.Position.X - p1.X, Cursor.Position.Y - p1.Y); 
      control.Location = p; 
      p1 = Cursor.Position; 
     } 
    } 
} 

は、親クラスが `System.Windows.Forms`ではない、それはちょうどだExtenderのプロバイダ

+0

ジェネリックパラメータはここでも扱います:[フォームのコントロール用のテンプレート関数を作成するにはどうすればいいですか?](http://stackoverflow.com/a/35946076/3110834) –

関連する問題