2017-01-28 7 views
2

申し訳ありませんが、このが重複している必要がありますが、この質問に対する回答をStackOverflowで見つけることができませんでした。私は複数の継承が不可能であることを知っています。多くのカスタムユーザーコントロールが同じインターフェイスを実装しています。同じコードを複製することを避ける方法はありますか?

私のアプリケーションには、50種類のカスタムユーザーコントロールがあり、すべてが自分のIParamConfigインターフェイスを実装しています。

IParamConfigは、5つのプロパティと8つのメソッドを定義します。これらのカスタムユーザーコントロールの

、いくつかは、などのTextBox、ボタンからいくつか、チェックボックスからいくつか、コンボボックスからいくつか、継承

私はメソッドとIParamConfigのプロパティを実装ParamConfigクラスを作成することができます。私は自分のカスタムユーザーコントロールクラスのそれぞれがParamConfigとTextBoxまたは他のユーザーコントロールクラスの両方から継承することができないことを知っています。

したがって、IParamConfigのメソッドとプロパティの実装を複数回複製することを余儀なくされています。

たとえば、TextBoxから継承し、IParamConfigのメソッドとプロパティを実装する抽象クラスAbtrParamConfigTextBoxを作成しました。この抽象クラスを継承する多くのTextBoxのようなカスタムユーザーコントロールを作成しました。

同様に、ComboBoxを継承し、IParamConfigのメソッドとプロパティも実装する抽象クラスAbtrParamConfigComboBoxを作成しました。合計で

Custom user controls inherit from various standard user controls

、Iは、(ピクチャ内の赤のボックス)12回共通のコードを複製しなければなりませんでした。

共通コードが1回しか表示されない場合、私はそれが大好きです。

たとえば、すべてのカスタムユーザーコントロールに同じクラス(ParamConfig)を継承させることができれば、それが大好きです。

All custom user controls inherit from a single class

enter image description here

Iは、単一のテキストボックスが含まれていることを、ユーザーコントロールを継承ParamConfigクラスを作成し、次にParamConfigから継承ParamConfigTextBoxを作成していることをやってみました。

Single Parent class

しかしParamConfigTextBoxからプロパティをコピーするために、私はもはやParamConfigTextBoxでテキストボックスのプロパティに直接アクセスすることが、私はParamConfigTextBoxでそれらを複製する必要がある、とのコードを追加しますので、それは、厄介な回避策が生じていませんTextBoxに追加します。醜い。

質問:私は、共通のコードを12回を複製することで立ち往生

アム?

私はUserControlから継承している共通クラスのアプローチを追求すべきでしょうか?

また、クリーナーソリューションはありますか?

EDIT:要求されたユーザーインターフェイスのスクリーンショット。 enter image description here これには〜100個のタブがあり、それぞれがユーザーコントロールで製品を構成します。

EDIT:

インタフェース:

// Functions 
    string BmsParamName { get; } // Name of the parameter in the BMS's memory associated with this control 
    void InitControlOnLoad(); // Initialize the control after load 
    void ClearCtrl(); // Clear this control 
    uint BitsUsedMask(); // Return the mask for the bits used in memory 
    void ShowValue16(ushort paramWord, bool isBadData); // Update the value or state displayed by this control 
    void ShowValue32(uint paramValue32, bool isBadData); // Update the value or state displayed by this control 
    uint NoOfBmsMemWords(); // Return the number of BMS memory words that this set uses 
    void ShowParamArray(uint[] paramValues, uint bmsMemOfst, bool isBadData); // Update the value or state displayed by this control 
    ushort GetEntry16(ushort configWord); // Receive the full word of configuration data and return it after replacing those bits that this configuration control is responsible for 
    uint GetEntry32(); // Return the value in this control as a 16 bit unsigned integer 
    ushort[] GetEntryArray(); // Get the set of configuration words for this configuration control 

プロパティ:

#region Properties (Protected properties, available to inherited classes) 

    // Name of BMS variable 
    protected string bmsParamName = ""; 
    [DefaultValueAttribute(0), Category("_Vinci"), 
    Description("Name of the variable in the BMS's memory associated with this control")] 
    public string BmsParamName 
    { 
     get { return bmsParamName; } 
     set { bmsParamName = value; } 
    } 

    // Conversion factor 
    protected float conversionFactor = 1F; 
    [DefaultValueAttribute(1), 
    Description("To convert the BMS value to the value shown in this setting, divide by this factor"), 
    Category("_Vinci")] 
    public float ConversionFactor 
    { 
     get { return conversionFactor; } 
     set { conversionFactor = value; } 
    } 

    // Width of the data 
    protected VinciForm.DataWidth dataWidth = VinciForm.DataWidth.Data16; 
    [DefaultValueAttribute(VinciForm.DataWidth.Data16), 
    Description("Whether the data in the BMS fill an entire 32 bit word, a 16 bit Word, just the top 8 bits (MSB), the lower 8 bits (LSB), or specific bits"), 
    Category("_Vinci")] 
    public VinciForm.DataWidth DataWidth 
    { 
     get { return dataWidth; } 
     set 
     { 
      dataWidth = value; 
      firstBitNo = 0u; 
      switch (dataWidth) 
      { 
       case VinciForm.DataWidth.Data32: 
        noOfBits = 32u; 
        break; 

       case VinciForm.DataWidth.Data16: 
        noOfBits = 16u; 
        break; 

       case VinciForm.DataWidth.Data8LSB: 
        noOfBits = 8u; 
        break; 

       case VinciForm.DataWidth.Data8MSB: 
        firstBitNo = 8u; 
        noOfBits = 8u; 
        break; 

       case VinciForm.DataWidth.DataBits: 
        noOfBits = 16u; 
        break; 
      } 
     } 
    } 

    // Number of the least significant bit used 
    protected uint firstBitNo = 0u; 
    [DefaultValueAttribute(0), Category("_Vinci"), 
    Description("Number of the least significant bit used")] 
    public uint FirstBitNo 
    { 
     get { return firstBitNo; } 
     set { firstBitNo = value; } 
    } 

    // Number of bits used 
    protected uint noOfBits = 16u; 
    [DefaultValueAttribute(3), Category("_Vinci"), 
    Description("Number of bits used")] 
    public uint NoOfBits 
    { 
     get { return noOfBits; } 
     set { noOfBits = value; } 
    } 

    // Display format: unsigned, signed or hex 
    protected VinciForm.DisplayFormat displayFrmtCode = VinciForm.DisplayFormat.UnsignedFormat; 
    [DefaultValueAttribute(VinciForm.DataWidth.Data16), 
    Description("Display format: unsigned, signed or hex"), 
    Category("_Vinci")] 
    public VinciForm.DisplayFormat DisplayFormat 
    { 
     get { return displayFrmtCode; } 
     set { displayFrmtCode = value; } 
    } 

    // Format string 
    protected string displayFrmtStr = ""; 
    [DefaultValueAttribute(""), 
    Description("Display format string (e.g.: F4 for 4 decimal places); leave blank for automatic"), 
    Category("_Vinci")] 
    public virtual string DisplayFrmtStr 
    { 
     get { return displayFrmtStr; } 
     set { displayFrmtStr = value; } 
    } 

    #endregion 
+1

インターフェイスを確認するとよいでしょう。さもなければ、回答は曖昧になります。 – Sefe

+0

なぜあなたはTextBoxに直接アクセスできませんか?非公開にしましたか?保護されたアクセス修飾子を持つプロパティーとして追加する場合、子クラスはそれを直接使用できなければなりません。 – chadnt

+0

@Sefeユーザーインターフェイスのスクリーンショットを追加しました –

答えて

1

あなたのインタフェースが実装するコントロール(少なくともないあなたの例のプロパティのいずれかのプロパティにアクセスしていないようです)。つまり、それらを自分のクラスにカプセル化して再利用するのはかなり容易でなければならないということです。コントロールのいくつかのプロパティにアクセスする場合でも、インターフェイスを別のクラスに実装し、コールバックメソッドなどのテクニックを使用してコントロール固有の部分にアクセスすることができます(例を挙げることはできません。ポストのインターフェース)。

このクラスのインスタンスをコントロールで使用して、コントロールを実装および再利用コードに保存できます。これは、実際には多くの一般的なデザインパターン(ブリッジ、ビジター、アダプターなど)です:継承を合成で置き換えます。

私のポイントを説明するために、私はあなたのインターフェイスの簡易版を使用します。

interface IParamConfig 
{ 
    string BmsParamName 
    { 
     get; 
     set; 
    } 

    float ConversionFactor 
    { 
     get; 
     set; 
    } 
} 

をあなたは別のヘルパークラスでこれを実装します:

public class ParamConfig : IParamConfig 
{ 
    private string bmsParamName = ""; 
    [DefaultValueAttribute(0), 
    Description("Name of the variable in the BMS's memory associated with this control")] 
    public string BmsParamName 
    { 
     get { return bmsParamName; } 
     set { bmsParamName = value; } 
    } 

    // Conversion factor 
    private float conversionFactor = 1F; 
    [DefaultValueAttribute(1), 
    Description("To convert the BMS value to the value shown in this setting, divide by this factor")] 
    public float ConversionFactor 
    { 
     get { return conversionFactor; } 
     set { conversionFactor = value; } 
    } 
} 

私はのための属性の一部を残しましたこれはヘルパークラスでも、プロパティエディタです。私はなぜそれをやったのか後で分かります。あなたが近いあなたの現在の実装に滞在したい場合は、あなたがコントロール上IParamConfigを実装し、ヘルパークラスの機能を転送することができます。

public class ParamConfigTextBox : TextBox, IParamConfig 
{ 
    private readonly ParamConfig paramConfig = new ParamConfig(); 

    [DefaultValueAttribute(0), Category("_Vinci"), 
    Description("Name of the variable in the BMS's memory associated with this control")] 
    public string BmsParamName 
    { 
     get { return paramConfig.BmsParamName; } 
     set { paramConfig.BmsParamName = value; } 
    } 

    // Conversion factor 
    [DefaultValueAttribute(1), 
    Description("To convert the BMS value to the value shown in this setting, divide by this factor"), 
    Category("_Vinci")] 
    public float ConversionFactor 
    { 
     get { return paramConfig.ConversionFactor; } 
     set { paramConfig.ConversionFactor = value; } 
    } 
} 

確かに、これらの2つのプロパティがにオフロードするために少し単純すぎるように見えますヘルパークラスですが、そこにすべてを持ち込み、さらに複雑なものにするため、全体的に最適なコードの再利用を実現します。

このソリューションの欠点は、すべてのコントロールにインターフェイス全体を実装する必要があることです。 の機能はあなたのヘルパークラスですが、実装のフットワークをかなりの回数行う必要があります。

interface IParamConfigProvider 
{ 
    IParamConfig ParamConfig 
    { 
     get; 
    } 
} 

public class ParamConfigTextBox : TextBox, IParamConfigProvider 
{ 
    private readonly paramConfig = new ParamConfig(); 

    [Category("_Vinci"), 
    Description("The param config properties")] 
    public ParamConfig ParamConfig 
    { 
     get { return paramConfig; } 
    } 

    IParamConfig IParamConfigProvider.ParamConfig 
    { 
     get { return ParamConfig; } 
    } 
} 

あなたはまだあなたのビジュアルデザイナであなたのIParamConfigのproprtiesをナビゲートすることができます:あなたは(それは完全なインタフェース、無簡略化した例です。この時間)を実装する方がはるかに簡単ですプロバイダインタフェースを作成することによって、あなたのタスクを簡素化することができます(デザイナーの属性をいくつか保持していたことを覚えておいてください - なぜ今はエディターにプロパティが表示されているのか分かります)。これがコントロールレベルでこれを実装する最も簡単な方法ですが、IParamConfigにアクセスするコードはIParamConfigProviderを通過するように変更する必要があります。最終的には、あなたのために役立つものがあなたの選択です。

+0

うわー! OK、私はそれをほとんど得ます。それを完全に消化するまでには時間がかかります。私はあなたが行っているのを見て、私はそれが好きです。私はそれを遊んだ後、私はあなたに戻ってきます、ありがとう! –

+1

XAMLを使用していないのは、添付プロパティを使用するだけで済みます。 –

+0

@Michael Puckett II:私にそれを知らせてくれてありがとう。 –

関連する問題