在两个用户控件和主窗体之间传递对象

Arm*_*nAH 1 c# user-controls winforms

因此,我有一个用作导航栏的主窗体和两个显示一些控件的用户控件。
UserControlsA有一些需要填写的字段。使用这些数据,我创建了一个包含一些信息的对象。我需要将该对象传递给,UserControlsB以便我可以在那里显示一些数据。

我的想法是创建该对象的三个实例,一个在 中UserControlsA用于获取该对象所需的信息,一个在主窗体中用于从 中获取该对象的“副本” UserControlsA,一个在其中UserControlsB可以从主窗体中获取信息形式。

然而,这似乎是多余的,甚至不起作用。这是一些代码:

主要形式:

public partial class main : Form
{
    public Object object { get; set; }
    public UCA uca;
    public UCB ucb;

    public Form1()
    {
        InitializeComponent();

        uca = new UCA();
        ucb = new UCB();

        panel2.Controls.Add(uca);
        panel2.Controls.Add(ucb);

        ucb.Visible = false;
        uca.Visible = true;

    }

    private void button1_Click(object sender, EventArgs e)
    {
        ucb.Visible = false;
        uca.Visible = true;
    }

    private void button2_Click(object sender, EventArgs e)
    {
        ucb.Visible = true;
        uca.Visible = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

用户控件A

public partial class UCA : UserControl
{
    public Object object { get; set; }
    
    public UCA()
    {
        InitializeComponent();
    }

    private void bUsage_Click(object sender, EventArgs e)
    {
        //Data is provided
        object = new Object(data);

        //I use var parent to try and access the object from the main form.
        var parent = Parent as Form1;
        object = parent.object;
    }
 }

        
Run Code Online (Sandbox Code Playgroud)

用户控制B

public partial class UCB : UserControl
{
    public Object object { get; set; }

    public UCB()
    {
        InitializeComponent();
    }

    public void updateData()
    {
        //I try to assign the object from the main form to this form's object.
        var parent = Parent as Form1;
        object = parent.object;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用 var Parent 不起作用。我能做些什么?

Jim*_*imi 5

几个使用INotifyPropertyChanged接口的示例以及使用标准公共事件的实现。

\n

相关文档:
\n Windows 窗体数据绑定
\n Windows 窗体数据绑定中的更改通知
\n与数据绑定相关的接口

\n

使用INotifyPropertyChanged
\nUserControl 公开一个公共属性(这里,在第一个示例中名为CustomDataObject简单类型,在第二个示例中。当然它可以是其他类型)。\n该属性用Bindable属性修饰。这里更多的是意图的描述,没有附加模板。\n添加了另外两个标准属性:stringobject
BindingDirection

\n
    \n
  • DefaultValue定义属性的默认值(创建控件时分配给属性的值)。代码生成器使用它来确定是否应序列化当前值:如果它与属性设置的值匹配,则不会序列化。
    \nPropertyGrid 还使用它以粗体显示非默认值选择或分配。
  • \n
  • DesignerSerializationVisibility指定属性在设计时应如何序列化。此处,设置为DesignerSerializationVisibility.Visible,表示应序列化该属性。
  • \n
\n

接口INotifyPropertyChanged可以被视为一种简化的方法,使用相同的事件处理程序将属性绑定添加到多个属性,以通知值的更改。
\n接口的默认实现只需要将PropertyChangedEventHandler类型的公共事件添加到类中。
\n当属性值更改时,设置器仅调用事件。执行此操作的方法略有不同;这里我使用的OnPropertyChanged()方法使用CallerMemberName属性来获取调用它的属性的名称。它在 WinForms 和 WPF 中相当常见。

\n
\n

UCA UserControl
\nUserControl(请参阅可视示例)有两个可更改绑定属性CustomDataObject值的按钮。他们的Click行动由 处理 ButtonsAction_Click

\n
using System.ComponentModel;\nusing System.Runtime.CompilerServices;\nusing System.Windows.Forms;\n\npublic partial class UCA : UserControl, INotifyPropertyChanged\n{\n    public event PropertyChangedEventHandler PropertyChanged;\n    private string m_DataObject = string.Empty;\n\n    public UCA() => InitializeComponent();\n\n    [Bindable(true, BindingDirection.TwoWay), DefaultValue("")]\n    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]\n    public string CustomDataObject {\n        get => m_DataObject;\n        set {\n            if (m_DataObject != value){\n                m_DataObject = value;\n                OnPropertyChanged();\n            }\n        }\n    }\n\n    private void OnPropertyChanged([CallerMemberName] string propertyName = "") =>\n        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n\n    private void ButtonsAction_Click(object sender, EventArgs e)\n    {\n        var btn = sender as Button;\n        CustomDataObject = (btn == SomeButton) ? txtInput1.Text : txtInput2.Text;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

UCB UserControl :
\n这个另一个 UserControl 是接收者。它只是公开了一个ReceiverDataObject将绑定到CustomDataObjectUCA 属性的公共属性 ( )。

\n

ReceiverDataObject属性也被定义为[Bindable],目的使其仅是单向的。该属性不会引发任何事件。它接收一个值,将其存储在私有字段中并设置内部 UI 元素。

\n
public partial class UCB : UserControl\n{\n    private string m_RecvDataObject = string.Empty;\n\n    public UCB() => InitializeComponent();\n\n    [Bindable(true, BindingDirection.OneWay)]\n    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]\n    public string ReceiverDataObject {\n        get => m_RecvDataObject;\n        set {\n            m_RecvDataObject = value;\n            txtPresenter.Text = m_RecvDataObject;\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

使用标准事件通知:
\n您还可以使用标准事件生成属性更改通知。
\n不同之处在于,每个属性都需要一个事件来通知更改。
\n如果您已经为此使用了事件委托,那么它可能是一个不错的选择,因为需要添加的内容很少:只需调用在属性设置器中引发事件的受保护方法即可。

\n

在这里,我使用常见的 .Net 事件处理,使用由底层 Component 类定义并由其Events属性公开的EventHandlerList来添加删除事件订阅。\n事件通常是通过调用与事件同名(前缀除外)的受保护方法来引发的。\n这里,Event =>方法。
On
CustomDataObjectChangedOnCustomDataObjectChanged()
\n您可以在所有标准控件中看到这种模式。

\n

\xe2\x96\xb6CustomDataObjectChanged分配给事件的名称不是一个选择:该事件必须具有与属性相同的名称和后缀Changed
\n这就是模式,遵循它就足够了。

\n

UCA用户控制

\n
public partial class UCA : UserControl\n{\n    private static readonly object Event_CustomDataObjectChanged = new object();\n    private object m_DataObject = null;\n\n    public UCButtonActions() => InitializeComponent();\n\n    [Bindable(BindableSupport.Yes, BindingDirection.TwoWay), DefaultValue(null)]\n    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]\n    public object CustomDataObject {\n        get => m_DataObject;\n        set {\n            if (m_DataObject != value){\n                m_DataObject = value;\n                OnCustomDataObjectChanged(EventArgs.Empty);\n            }\n        }\n    }\n\n    public event EventHandler CustomDataObjectChanged {\n        add {\n            Events.AddHandler(Event_CustomDataObjectChanged, value);\n        }\n        remove {\n            Events.RemoveHandler(Event_CustomDataObjectChanged, value);\n        }\n    }\n\n    protected virtual void OnCustomDataObjectChanged(EventArgs e)\n    {\n        if (Events[Event_CustomDataObjectChanged] is EventHandler evth) evth(this, e);\n    }\n}  \n
Run Code Online (Sandbox Code Playgroud)\n

UCB 用户控制
\n第二个 UserControl 不变。这只是接收器。

\n
\n

Form 类(或用作 Handler 的另一个类):

\n

在表单构造函数或表单初始化后调用的任何其他方法中,使用DataBindings属性来链接两个 UserControl 的属性:

\n
public SomeForm()\n{\n    InitializeComponent();\n    ucb1.DataBindings.Add("ReceiverDataObject", uca1, "CustomDataObject", \n        false, DataSourceUpdateMode.OnPropertyChanged);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

您还可以使用 BindingSource 进行调解:

\n
BindingSource ucsSource = null;\n\npublic SomeForm()\n{\n    InitializeComponent();\n    ucsSource = new BindingSource(uca1, null);\n    ucb1.DataBindings.Add("ReceiverDataObject", ucsSource, "CustomDataObject", \n        false, DataSourceUpdateMode.OnPropertyChanged);\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

示例功能:

\n

用户控件双向数据绑定

\n