48

まず、これはASP.NETの質問ではなく、Windows フォームを使用するデスクトップ アプリケーションに関する質問です。

他のフォームのコントロールを操作する必要があります。たとえば、次のようにしてコントロールにアクセスしようとしています...

otherForm.Controls["nameOfControl"].Visible = false;

それは私が期待するようには機能しません。から例外がスローされてしまいMainます。ただし、public代わりにコントロールを作成するとprivate、それらに直接アクセスできるようになります...

otherForm.nameOfControl.Visible = false;

しかし、それはそれを行うための最良の方法ですか?他のフォームでコントロールpublicを作成することは「ベスト プラクティス」と見なされますか? 別のフォームのコントロールにアクセスする「より良い」方法はありますか?

さらなる説明:

これは実際には、私が行った別の質問「C# で「ツリー ビュー設定ダイアログ」タイプのインターフェイスを作成するための最良の方法は? . 私が得た答えは素晴らしく、実行時と設計時の両方で UI をまっすぐに保ち、使いやすくするという点で私が抱えていた多くの組織的な問題を解決しました。ただし、インターフェイスの他の側面を簡単に制御するという、この 1 つの厄介な問題が発生しました。

基本的に、ルートフォームのパネルにある他の多くのフォームをインスタンス化するルートフォームがあります。したがって、たとえば、これらのサブフォームの 1 つのラジオ ボタンは、メインのルート フォームのステータス ストリップ アイコンの状態を変更する必要がある場合があります。その場合、親 (ルート) フォームのステータス ストリップにあるコントロールと対話するサブフォームが必要です。(「誰が最初に」のような方法ではなく、それが理にかなっていることを願っています。)

4

17 に答える 17

38

コントロールをパブリックにする代わりに、その可視性を制御するプロパティを作成できます。

public bool ControlIsVisible
{
     get { return control.Visible; }
     set { control.Visible = value; }
}

これにより、コントロールのプロパティ セット全体を公開しない、そのコントロールへの適切なアクセサーが作成されます。

于 2008-08-12T07:41:07.093 に答える
20

私は個人的にそれをしないことをお勧めします...何らかのアクションに応答していて、その外観を変更する必要がある場合は、イベントを発生させてそれを整理することをお勧めします...

このようなフォーム同士の結合は、いつも私を緊張させます。私は常に、UI を可能な限り軽量で独立したものに保つようにしています..

これが役立つことを願っています。そうでない場合は、シナリオを拡張できますか?

于 2008-08-12T07:35:33.000 に答える
8

最初のものはもちろん機能していません。フォーム上のコントロールはプライベートであり、設計上、そのフォームに対してのみ表示されます。

それをすべて公開することも最善の方法ではありません。

何かを外の世界に公開したい場合 (これは別の形を意味する場合もあります)、そのためのパブリック プロパティを作成します。

public Boolean nameOfControlVisible
{
    get { return this.nameOfControl.Visible; }
    set { this.nameOfControl.Visible = value; }
}

このパブリック プロパティを使用して、コントロールを表示または非表示にしたり、コントロールの現在の可視性プロパティを確認したりできます。

otherForm.nameOfControlVisible = true;

完全なコントロールを公開することもできますが、多すぎると思います。現在のフォームの外部から本当に使用したいプロパティのみを表示する必要があります。

public ControlType nameOfControlP
{
    get { return this.nameOfControl; }
    set { this.nameOfControl = value; }
}
于 2008-08-12T07:42:57.603 に答える
5

追加の詳細を読んだ後、robcthegeek : raise an event に同意します。カスタム EventArgs を作成し、必要なパラメーターを渡します。

于 2008-08-12T07:48:18.200 に答える
3

2 つのフォームがあり、あるフォームのプロパティを別のフォームで非表示にしたいとします。

form1 ob = new form1();
ob.Show(this);
this.Enabled= false;

form2ボタンを介してform1にフォーカスを戻したい場合は、次のようにします。

Form1 ob = new Form1();
ob.Visible = true;
this.Close();
于 2012-01-31T12:14:46.697 に答える
2

これを親フォームで処理します。イベントを通じて、それ自体を変更する必要があることを他のフォームに通知できます。

于 2008-08-12T07:40:55.690 に答える
2
  1. イベント ハンドラーを使用して、フォームを処理するように他のフォームに通知します。
  2. 子フォームにパブリック プロパティを作成し、親フォームからアクセスします (有効なキャストを使用)。
  3. フォームの初期化パラメータを設定するために、子フォームに別のコンストラクタを作成します
  4. カスタム イベントを作成したり、(静的) クラスを使用したりします。

非モーダル フォームを使用している場合のベスト プラクティスは #4 です。

于 2011-06-22T21:36:59.060 に答える
1

あなたはできる

  1. 子フォームに必要なパラメーターを使用してパブリックメソッドを作成し、親フォームから呼び出します(有効なキャストを使用)
  2. 子フォームにパブリックプロパティを作成し、親フォームからアクセスします(有効なキャストを使用)
  3. フォームの初期化パラメーターを設定するために、子フォームに別のコンストラクターを作成します
  4. カスタムイベントを作成するか、(静的)クラスを使用します

非モーダルフォームを使用している場合のベストプラクティスは#4です。

于 2009-04-14T10:06:36.053 に答える
1

プロパティ (強調表示) を使用して、MainForm クラスのインスタンスを取得できます。しかし、これは良い習慣ですか?おすすめは何ですか?

このために、OnLoad メソッドで実行されるプロパティ MainFormInstance を使用します。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LightInfocon.Data.LightBaseProvider;
using System.Configuration;

namespace SINJRectifier
{

    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            UserInterface userInterfaceObj = new UserInterface();
            this.chklbBasesList.Items.AddRange(userInterfaceObj.ExtentsList(this.chklbBasesList));
            MainFormInstance.MainFormInstanceSet = this; //Here I get the instance
        }

        private void btnBegin_Click(object sender, EventArgs e)
        {
            Maestro.ConductSymphony();
            ErrorHandling.SetExcecutionIsAllow();
        }
    }

    static class MainFormInstance  //Here I get the instance
    {
        private static MainForm mainFormInstance;

        public static MainForm MainFormInstanceSet { set { mainFormInstance = value; } }

        public static MainForm MainFormInstanceGet { get { return mainFormInstance; } }
    }
}
于 2011-05-13T19:30:06.157 に答える
1

このためにイベントを使用することに同意します。あなたは MDI アプリケーションを作成していて (多くの子フォームを作成しているため)、ウィンドウを動的に作成していて、イベントのサブスクライブを解除するタイミングがわからないのではないかと思われるため、Weak Event Patternsを参照することをお勧めします。残念ながら、これはフレームワーク 3.0 および 3.5 でのみ利用可能ですが、弱い参照を使用して同様のものをかなり簡単に実装できます。

ただし、フォームの参照に基づいてフォーム内のコントロールを見つけたい場合は、フォームのコントロール コレクションを調べるだけでは十分ではありません。すべてのコントロールには独自のコントロール コレクションがあるため、特定のコントロールを見つけるには、それらすべてを再帰する必要があります。これらの 2 つの方法でこれを行うことができます (改善される可能性があります)。

public static Control FindControl(Form form, string name)
{
    foreach (Control control in form.Controls)
    {
        Control result = FindControl(form, control, name);

        if (result != null)
            return result;
    }

    return null;
}

private static Control FindControl(Form form, Control control, string name)
{
    if (control.Name == name) {
        return control;
    }

    foreach (Control subControl in control.Controls)
    {
        Control result = FindControl(form, subControl, name);

        if (result != null)
            return result;
    }

    return null;
}
于 2008-08-12T14:36:54.180 に答える
0

より複雑なコントロール/モジュール/コンポーネントを作成している場合は、あるビューのコンテンツに別のビューからのみアクセスする必要があります。それ以外の場合は、標準の Model-View-Controller アーキテクチャを使用してこれを行う必要があります。関心のあるコントロールの有効な状態を、適切な情報を提供するモデル レベルの述語に接続する必要があります。

たとえば、必要な情報がすべて入力されたときにのみ [保存] ボタンを有効にしたい場合は、そのフォームを表すモデル オブジェクトが保存可能な状態になったことを伝える predicate メソッドが必要です。次に、ボタンを有効にするかどうかを選択するコンテキストで、そのメソッドの結果を使用します。

これにより、ビジネス ロジックとプレゼンテーション ロジックがより明確に分離され、両方がより独立して進化できるようになり、複数のバックエンドを持つ 1 つのフロントエンド、または単一のバックエンドを持つ複数のフロントエンドを簡単に作成できます。

また、「 Trust But Verify」パターンに従うことができるため、単体テストと受け入れテストを作成するのがはるかに簡単になります。

  1. モデル オブジェクトをさまざまな方法で設定する 1 セットのテストを作成し、"is savable" 述語が適切な結果を返すことを確認できます。

  2. 保存ボタンが適切な方法で「is savable」述語に接続されているかどうかを確認する別のセットを作成できます (それがフレームワークに関係なく、Mac OS X 上の Cocoa では、これは多くの場合バインディングを介して行われます)。

両方のテスト セットに合格している限り、ユーザー インターフェイスが希望どおりに動作することを確信できます。

于 2008-08-17T01:23:36.650 に答える
0

子フォームは本当に Form である必要がありますか? 代わりにユーザー コントロールを使用できますか? このようにして、メイン フォームが処理するイベントを簡単に発生させることができ、そのロジックを 1 つのクラスにカプセル化することができます (少なくとも、論理的には、それらは既にすべてのクラスの後にあります)。

@Lars: あなたはここにいます。これは私が最初の頃に行ったことであり、それ以来行う必要はありませんでした。そのため、最初にイベントを発生させることを提案しましたが、他の方法ではカプセル化の外観が実際に壊れてしまいます。

@ロブ:うん、ほぼ正しいですね:)。これで0/2...

于 2008-08-12T07:55:55.207 に答える
0

@Lars、フォーム参照の受け渡しに関する良い呼び出しは、私自身もそれを見ました。汚い。ただし、それらが BLL レイヤーに渡されるのを見たことはありません! それも意味がありません!それはパフォーマンスに深刻な影響を与えた可能性がありますよね? BLL のどこかに参照が保持されている場合、フォームはメモリに残りますか?

あなたは私の同情を持っています!;)


@Ed、フォーム UserControls の作成に関するコメントを RE してください。Dylan はすでに、ルート フォームが多くの子フォームをインスタンス化し、MDI アプリケーションの印象を与えていることを指摘しています (ユーザーがさまざまなフォームを閉じたいと思うかもしれません)。この仮定が正しければ、それらはフォームとして保持するのが最善だと思います。確かに修正の余地があります:)

于 2008-08-12T07:57:25.453 に答える
0

ステップ1:

string regno, exm, brd, cleg, strm, mrks, inyear;

protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
    string url;
    regno = GridView1.Rows[e.NewEditIndex].Cells[1].Text;
    exm = GridView1.Rows[e.NewEditIndex].Cells[2].Text;
    brd = GridView1.Rows[e.NewEditIndex].Cells[3].Text;
    cleg = GridView1.Rows[e.NewEditIndex].Cells[4].Text;
    strm = GridView1.Rows[e.NewEditIndex].Cells[5].Text;
    mrks = GridView1.Rows[e.NewEditIndex].Cells[6].Text;
    inyear = GridView1.Rows[e.NewEditIndex].Cells[7].Text;

    url = "academicinfo.aspx?regno=" + regno + ", " + exm + ", " + brd + ", " +
          cleg + ", " + strm + ", " + mrks + ", " + inyear;
    Response.Redirect(url);
}

ステップ2:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        string prm_string = Convert.ToString(Request.QueryString["regno"]);

        if (prm_string != null)
        {
            string[] words = prm_string.Split(',');
            txt_regno.Text = words[0];
            txt_board.Text = words[2];
            txt_college.Text = words[3];
        }
    }
}
于 2011-06-29T08:24:32.630 に答える
0

これは、プレゼンテーションをデータ モデルから分離するための最有力候補のようです。この場合、設定は、特定のプロパティが変更されるたびにイベントの更新を発生させる別のクラスに保存する必要があります (プロパティが個別のセットである場合は INotifyPropertyChanged を調べ、より自由な形式のテキストベースのキーである場合は単一のイベントを調べます)。 )。

ツリー ビューで設定モデルを変更すると、イベントが発生します。In your other forms, you'll subscribe to the changes that you're interested in. プロパティの変更をサブスクライブするために使用するイベント ハンドラーでは、 this.InvokeRequired を使用して、UI を作成する適切なスレッドにいるかどうかを確認します。そうでない場合は、this.BeginInvoke を使用して目的のメソッドを呼び出し、フォームを更新します。

于 2008-09-07T18:20:44.037 に答える
0

修飾子を public から internal に変更します。.Net は、プロジェクトからメソッド/プロパティ/コントロールへの不正なアクセスを防止するため、public ではなく private 修飾子を意図的に使用します。実際、 public 修飾子はどこからでもアクセスできるため、非常に危険です。プロジェクト外のすべてのボディが、メソッド/プロパティにアクセスできます。ただし、内部修飾子では、ボディ (現在のプロジェクトの他のもの) はメソッド/プロパティにアクセスできません。

いくつかの秘密のフィールドを持つプロジェクトを作成しているとします。したがって、これらのフィールドがプロジェクトからアクセスできる場合、それは危険であり、最初のアイデアに反する可能性があります. 良い推奨事項の 1 つとして、public 修飾子の代わりに internal 修飾子を常に使用すると言えます。

しかし、いくつかの奇妙な!

私たちのメソッド/プロパティはまだプライベートですが、VB.Netでも通知する必要があります.formを変数として呼び出すことで、他のフォーム/クラスからアクセスできますが、他に問題はありません。

このプログラミング言語の動作が C# と異なる理由がわかりません。両方とも同じプラットフォームを使用しており、ほぼ同じバックエンド プラットフォームであると主張していますが、ご覧のとおり、動作は異なります。

しかし、私はこの問題を2つのアプローチで解決しました。また; インターフェイスを使用する (ご存知のように、これはお勧めできません。通常、インターフェイスには public 修飾子が必要であり、public 修飾子を使用することはお勧めしません (上で説明したように))、

または

フォーム全体を静的クラスと静的変数のどこかに宣言しますが、内部修飾子がまだあります。次に、そのフォームをユーザーに表示するために使用すると思われる場合は、新しいForm()構築をその静的クラス/変数に渡します。今では、どこからでも好きなようにアクセスできます。しかし、まだ何かが必要です。フォームの Designer ファイルでも要素の内部修飾子を宣言します。フォームが開いている間は、どこからでもアクセスできます。それはあなたのために非常にうまくいくことができます。

この例を検討してください。

Form の TextBox にアクセスするとします。

したがって、最初の仕事は、静的クラスでの静的変数の宣言です (静的の理由は、将来新しいキーワークを使用せずに簡単にアクセスできるようにするためです)。

次に、他のフォームからアクセスされると想定されるそのフォームのデザイナー クラスに移動します。その TextBox 修飾子の宣言を private から internal に変更します。心配しないで; .Net は、変更後にプライベート修飾子に再度変更することはありません。

3番目に、そのフォームを呼び出して開く場合は、新しいフォーム構築をその静的変数-->>静的クラスに渡します。

第4; Fromが開いている間、他のフォームから(プロジェクト内のどこからでも)そのフォーム/コントロールにアクセスできます。

以下のコードを見てください (3 つのオブジェクトがあります。1- 静的クラス (この例では という名前を付けていますA)

2 - 最終的なフォームを開きたいその他のフォーム (この例では TextBox がありますFormB)。

3 - 開く必要がある実際のフォームであり、その内部にアクセスすると仮定しますTextBox1(この例ではFormC)。

以下のコードを見てください。

internal static class A
{
    internal static FormC FrmC;
}

FormB ...
{
    '(...)
    A.FrmC = new FormC();
    '(...)
}

FormC (Designer File) . . . 
{
     internal System.Windows.Forms.TextBox TextBox1;
}

FormCその静的変数 (こちら) とその内部コントロール (こちらTextbox1) にいつでもどこでもアクセスできますFormC


コメント/アイデアがあれば教えてください。このトピックについてあなたや他の団体からもっと聞いてうれしい. 正直なところ、私は過去にこの言及された問題に関していくつかの問題を抱えていました. 最善の方法は、うまくいくことを願っている2番目の解決策でした。新しいアイデア/提案があれば教えてください。

于 2016-08-16T22:12:04.587 に答える