簡體   English   中英

在 C# 中從 Form2 Button1_Click 更改 Form1 的 Label1.Text

[英]Changing the Label1.Text of Form1 from Form2 Button1_Click in C#

我正在嘗試通過從Form2觸發的Button1_Click更改我的Form1 (所有者)上的Label1.Text ,但Label1.Text沒有任何更改。 它仍然是空字符串(“”)。 我已經兩次/三次檢查了我的代碼。 我找不到任何問題。

這是我到目前為止所做的:

Form1
    // Label1 is inside the TabControl Page 0
    // Label1.Modifier property already set to public
    // and Label1.Text = ""

    public static FrmOwner Self;

    public FrmOwner()
    {
        InitializeComponent();
        Self = this;        
    }

    private void Button2_Click()
    {
        FrmForm2 frm = new FrmForm2 ();
        frm.ShowDialog();
    }

Form2
    public FrmForm2()
    {
        InitializeComponent();      
    }

    private void Button1_Click(object sender, EventArgs e)
    {
        FrmOwner.Self.Label1.Text = "Changed Text";
    }

我確定我的代碼肯定有問題。 請幫忙。

您可以將 Form1 實例傳遞給 Form2。 然后從 From2 訪問 From1 的公共方法和屬性。

表格1

public static FrmOwner Self;

public FrmOwner()
{
    InitializeComponent();
    Self = this;        
}

private void Button2_Click()
{
    FrmForm2 frm = new FrmForm2 (this);
    frm.ShowDialog();
}

public void SetLabel(string txt)
{
   Label1.Text = txt
}

表格2

private FrmForm1 _frm1;

public FrmForm2(FrmForm1 frm1)
{
    _frm1 = frm1;

    InitializeComponent();      
}

private void Button1_Click(object sender, EventArgs e)
{
    _frm1.SetLabel("New Text");
}

有幾種方法可以做到這一點。 傳遞您想要訪問的表單或控件/變量可能是最好的方法,因為它不會不必要地公開傳遞的控件/變量,並且所有內容都可以保密。

但是,如果您選擇以第一種形式公開控件/變量,這可以簡化。 在此示例中,form1 中的Label控件label1似乎是我們希望在 form2 中訪問的內容。 因此,一個非常簡單的方法是利用Forms Owner屬性,它應該如下所述工作。

首先,我們希望通過將 Form1 的Modifier屬性設置為public來公開 form1 的Label ... label1控件。

然后,當Form1創建並顯示Form2時……我們希望通過利用Forms Owner屬性將Form1傳遞給Form2 ,這通過在調用Form2ShowShowDialog時將Owner表單簡單地傳遞給Form2來完成。 像下面的東西......

Form2 f2 = new Form2();
f2.Show(this);

調用Show/ShowDialog方法時,請注意this作為參數。 這就是我們在第一種形式中需要做的所有事情。 Show/ShowDialog中的this參數會將被調用表單的Owner屬性設置為通用Form ,我們稍后可以將其轉換為被調用表單中的Form1對象。

然后在第二個Form2中,當我們想要訪問Form1 publiclylabel1 ……我們只需要將 form2 的Owner屬性轉換為Form1對象,因為Owner是一個“通用” Form對象。 所以,這看起來像……

private void button1_Click(object sender, EventArgs e) {
  ((Form1)Owner).label1.Text = "Hello from form2";
}

這就是所有需要的。

我一直很感興趣,到目前為止,我最同意的答案是 Enigmativity,但我覺得它還不足以將Form2的實現與Form1的實現分離。 我的建議是更接近MVVM設計模型,人們可以使用它來使代碼更易於維護和移植(例如,從長遠來看,我們可能希望有一天會制作這個應用程序的 iOS 和 Android 版本)。

考慮這個具有兩個(到目前為止)可綁定屬性VisibleBindableTextForm2 ,並在其中任何一個發生更改時發送通知。 現在, Form2上的Button在單擊時作用於BindableText屬性。

public partial class Form2 : Form, INotifyPropertyChanged
{
    public Form2() => InitializeComponent();

    private void buttonChangeText_Click(object sender, EventArgs e) =>
        BindableText = $"Clicks = {_count++}";

    static int _count = 1;

    string _BindableText = string.Empty;
    public string BindableText
    {
        get => _BindableText;
        set
        {
            if(!Equals(_BindableText, value))
            {
                _BindableText = value;
                OnPropertyChanged();
            }
        }
    }
    protected override void OnVisibleChanged(EventArgs e)
    {
        if (Visible && (Owner != null))
        {
            Location = new Point(
                Owner.Location.X + Owner.Width + 10,
                Owner.Location.Y
            );
        }
        OnPropertyChanged(nameof(Visible));
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

同時,主窗體Form1的簡化版本可能如下所示:

表格 1

當復選框變為 true 時,會在顯示新實例之前附加PropertyChanged事件。 然后,類似於 JohnG 的回答,我們調用ShowDialog(owner: this)來分配Owner屬性。 OnVisibleChanged覆蓋中,它的Location用於設置彈出窗口顯示時的相對位置。

private void checkBoxShowForm2_CheckedChanged(object sender, EventArgs e)
{
    if (((CheckBox)sender).Checked)
    {
        using (var form2 = new Form2())
        {
            form2.PropertyChanged += (sender, e) =>
            {
                switch (e.PropertyName)
                {
                    case nameof(form2.BindableText):
                        label1.Text = form2.BindableText;
                        break;
                    case nameof(form2.Visible):
                        checkBoxShowForm2.Checked = form2.Visible;
                        checkBoxShowForm2.Enabled = !form2.Visible;
                        break;
                }
            };
            form2.ShowDialog(owner: this);
        }
    }
}

相對位置和按鈕點擊

當屬性發生變化時, Form1會以它認為合適的方式做出響應:

  • BindingText改變時設置private label1Text屬性
  • Visible屬性變為 false 時,取消選中private checkBoxShowForm2

但是,重要的是,如果Form2未來對其內部實現細節進行更改,則Form1不會受到影響。


注意:Form2 需要處理

CharithJ 和 Enigmativity 的答案將受益於using語句,以防止ShowDialog調用中的資源泄漏。 Form.ShowDialog Method的官方 Microsoft 文檔指出,此處需要 using 塊(或其他處置方法):

因為顯示為對話框的窗體是隱藏的而不是關閉的,所以當您的應用程序不再需要該窗體時,您必須調用該窗體的 Dispose 方法。

它是這樣設計的,以便Form2可以移動,而不是一個局部變量,它可以是member ,實例化一次,並顯示關閉多次。 這樣的事情是可能的,因為它沒有處理它的Handle (當Form1處理時仍然需要處理它)。 但由於它目前被用作本地,它需要using

另一方面,JohnG 在Form2的本地新實例上使用Show(this)釋放句柄,但不會是模態的。 也就是說,它將在 Z 順序中保持在其所有者Form1的頂部,但不會阻止用戶與Form1的交互。

更慣用的方法是使用事件。

表格1

public class FrmForm1 : Form
{
    private void Button2_Click()
    {
        FrmForm2 frm = new FrmForm2();
        frm.LabelUpdated += FrmForm2_LabelUpdated;
        frm.ShowDialog();
    }

    private void FrmForm2_LabelUpdated(object sender, string txt)
    {
        Label1.Text = txt
    }
}

窗體2

public class FrmForm2 : Form
{
    public event EventHandler<string> LabelUpdated;

    private void Button1_Click(object sender, EventArgs e)
    {
        this.LabelUpdated?.Invoke(this, "New Text");
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM