【解決方法】TabControl タブが選択されたときにどのコントロールが表示されるかを識別する方法は?


やあ、

VB.NET 2008 Express Edition を使用して、TabControl にさまざまなタブを配置しました。 各タブには多数のコントロールが含まれています。 設計時に、これらの一部の Visible プロパティは False に設定されているため、プログラムの起動時に特定のアクションが実行されるまで非表示になっています。別のコードで、起動中に Visible プロパティが False になっているものを特定する必要があります。 .

control.Visible プロパティをプログラムでチェックすると、現在選択されていないタブ上のすべてのコントロールに対して False が返されます。 ただし、そのタブを選択すると、Visible プロパティが True であるすべてのコントロールが表示されます。 また、タブのテキスト ボックスの Text プロパティに文字列を割り当てたり、Text プロパティから文字列を読み取ったりすることもできます。 いいえ これは、選択されていないタブのコントロールのプロパティがまだ「ライブ」であることを示します。

Visible プロパティを使用しない場合、VB はどのコントロールを表示するかをどのように「認識」しますか? 親タブが選択されたときにどのコントロールが表示されるか、または表示されないかを知るために、同じロジックを利用したいと思います。

私はすでに Tag プロパティを使用しています。それ以外の場合は、Visible プロパティをミラーリングするために使用できます。 コントロール クラスの継承とカスタム プロパティの追加以外に、これを実現する簡単な方法はありますか?

ありがとう、
ジョン。

解決策 1

あなたの質問に答える前に、私の最善のアドバイスを教えてください。 どのコントロールが表示され、何が表示されないかを必要としないプログラミング手法を開発する. 私は本気です。 私にとって、そのような知識に依存することは、アプリケーションの設計が不十分であることを示しています。

それでは、考えられる普遍的な解決策の 1 つを説明します。 参照してください:

C#
using System.Collections.Generic;
using System.Windows.Forms;

// ...

    public partial class MyForm : Form { // this class does not have to be a form
   
        // ...
     
        class Visibility {
            internal Visibility(bool isVisible) { this.IsVisible = isVisible; } 
            internal bool IsVisible { get; set; }
        } //class Visibility

        Dictionary<Control, Visibility> visibilityMap = new Dictionary<Control, Visibility>();

        void SetVisibility(Control control, bool isVisible) {
            if (control == null) return;
            Visibility value;
            if (visibilityMap.TryGetValue(control, out value))
                value.IsVisible = isVisible;
            else
                visibilityMap.Add(control, new Visibility(isVisible));
            control.Visible = isVisible;
        } //SetVisibility

        bool IsLogicallyVisible(Control control) {
            Visibility value;
            if (visibilityMap.TryGetValue(control, out value))
                return value.IsVisible;
            else
                return control.Visible;
            // or, better use Debug.Assert requiring control to be
            // in the dictionary
        } //IsLogicallyVisible

    } //class MyForm

私の単純な考えが十分に明確であることを願っています。 ここで、いくつかの規律を適用する必要があります。すべての可視性は、 SetVisibility. 上記のアサーションは、この規則が破られているケースを明らかにするのに役立ちます。または、そのような違反を無視することができます。 この解決策は、上記の機能をすべて共有する複数のフォームに適用できるように一般化するのが簡単です。

解決策は、予想よりも一般的です。タブ コントロールについて知っている必要はありません (そうでなければ、努力する価値はありません)。

それで全部です。 結構簡単。 🙂

-SA

解決策 2

そして、解決策 1 の最初の段落で述べた代替解決策について詳しく説明します。可視性などの制御状態の知識に依存しない UI 技術を開発する方法です。 Enabled、ラベル テキストなど。

アイデアを得るために、次の適用可能性を学び、分析することをお勧めします 建築パターン (http://en.wikipedia.org/wiki/Architectural_pattern_(computer_science)[^]):

MVVM — モデル ビュー ビュー モデル、
http://en.wikipedia.org/wiki/Model_View_ViewModel[^]、

MVC — モデル ビュー コントローラー、
http://en.wikipedia.org/wiki/Model-view-controller[^])、

MVA — モデル – ビュー – アダプター、
http://en.wikipedia.org/wiki/Model–view–adapter[^]、

MVP — モデル ビュー プレゼンター、
http://en.wikipedia.org/wiki/Model-view-presenter[^].

これらのアーキテクチャの動機に注意してください。 それを理解すれば、より良いデザインのアイデアを生み出すことができるでしょう。 現時点では、これらのアーキテクチャや他の多くの合理的に考えられるアーキテクチャ (単純なアプリケーションの場合ははるかに単純になる可能性があります) では、これらのコントロールの状態を認識して UI 自体から取得する必要がない理由を説明しようと思います。

アイデアは、これは、データモデル、ビューモデルなど、より信頼性の高い統合されたデータソースがあるためです。 このモデルは、UI の状態をどのように変更する必要があるかについての情報源として機能しますが、その逆ではありません。 を取得するときに UI の状態を「読み取る」だけで済みます。 ユーザーが入力したもの: テキスト ボックス内のテキスト、チェック状態、リストとグリッドでの選択。 可視性などを「読み取る」ことはありません。 このような制御状態のデータ取得は一貫しており、1 つの論理ユニットに集中しており、多くの場合、バインドの背後に「隠されている」/カプセル化されているため、メンテナンスに適しています。 この統合的なアプローチとは対照的に、コード内に分散されたコントロールによる直接操作をスムーズにサポートすることはほぼ不可能です。 UI をアプリケーションの他のすべての側面から完全に分離する必要があることを理解する必要があります。

ところで、あなたが使用しようとしていたバインディングについて言及したように、それは魔法の杖ではありません。 適切な UI アーキテクチャがなければ、バインディングはプログラミングを純粋なシャーマニズムに変える可能性があります。 残念ながら、最近では、多くの素朴な初心者に常に起こります…

-SA

解決策 3

.NET フレームワークのソースコードを調べると、ここに掲載されているものよりもはるかに優れた解決策が見つかります。

Control クラスは、内部関数 GetState(STATE_VISIBLE) を使用して、親コントロールの可視性とは無関係に、Control が Visible = true または Visible = false に設定されているかどうかを判断します。

したがって、この関数はリフレクションによって取得する必要があります。 Reflection は遅いので、MethodInfo を非常に高速な Delegate に変換します。

private delegate bool delCtrlGetState(Control i_Ctrl, int s32_Flag);
private static delCtrlGetState mf_CtrlGetState;

static ConstructorOfYourClass()
{
   MethodInfo i_Method = typeof(Control).GetMethod("GetState", BindingFlags.NonPublic | BindingFlags.Instance);
   mf_CtrlGetState = (delCtrlGetState)Delegate.CreateDelegate(typeof(delCtrlGetState), i_Method);
}

public static bool IsCtrlVisible(Control i_Ctrl)
{
	// referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs
	// Line 170
	const int STATE_VISIBLE = 0x00000002;
	return mf_CtrlGetState(i_Ctrl, STATE_VISIBLE);
}

コメント

タイトルとURLをコピーしました