1

有人能告诉我如何在我的 UserControl 中有一个功能,可以让主机 windowsform 知道控件在做什么吗?

例如,我的用户控件有一个文件浏览器,如果用户使用这个文件浏览器打开一个文件,我想在表单的状态条栏中写“正在加载文件”。

这需要使用事件吗?如果是这样,我怎么能在 usercontrol 中有一个事件来报告它所做的任何事情(那么我想我必须在 usercontrol 的所有方法中调用这个事件)。

4

2 回答 2

2

简单的

是的,在表单可以订阅的用户控件上公开一个事件。您应该使用标准事件模式:

class MyUserControl : UserControl
{
    public event EventHandler<EventArgs> FileOpened;

    protected virtual void OnFileOpened(EventArgs e)
    {
        EventHandler<EventArgs> handler = FileOpened;
        if (handler != null)
            handler(this, e);
    }
}

然后,当文件打开时,您调用OnFileOpened(EventArgs.Empty)which 触发事件。

使用自定义 EventArgs

现在表单可能需要知道打开了什么文件。您可以在用户控件上公开表单可用于查找的属性,或者您可以在事件中提供该信息,如下所示:

public class FileOpenedEventArgs : EventArgs
{
    private string filename;
    public FileOpenedEventArgs(string filename)
    {
        this.filename = filename;
    }
    public string Filename { get { return filename; } }
}

class MyUserControl : UserControl
{
    public event EventHandler<FileOpenedEventArgs> FileOpened;

    protected virtual void OnFileOpened(FileOpenedEventArgs e)
    {
        EventHandler<FileOpenedEventArgs> handler = FileOpened;
        if (handler != null)
            handler(this, e);
    }
}

然后你用OnFileOpened(new FileOpenedEventArgs(filename)).

最佳

创建事件处理程序public event delegate Name;时,您正在为对象上的委托分配存储空间。对象(尤其是控件)通常有大量从未订阅过的事件。这是一大堆未使用的分配存储。框架中以EventHandlerList的形式内置了优化。这个方便的对象仅在实际使用时才存储事件处理程序。所有System.Windows.Forms.Control对象都派生自System.ComponentModel.Component,并且它已经提供了一个(受保护的)EventHandlerList,您可以在派生的 Control 中访问它。

要使用它,您首先创建一个唯一标识您的事件的静态对象,然后手动提供add {}和方法。remove {}像这样:

class MyUserControl : UserControl
{
    private static readonly object FileOpenedKey = new Object();
    public event EventHandler<FileOpenedEventArgs> FileOpened
    {
        add { Events.AddHandler(FileOpenedKey, value); }
        remove { Events.RemoveHandler(FileOpenedKey, value); }
    }

    protected virtual void OnFileOpened(FileOpenedEventArgs e)
    {
        var handler = (EventHandler<FileOpenedEventArgs>)Events[FileOpenedKey];
        if (handler != null)
            handler(this, e);
    }
}
于 2012-08-29T19:51:23.210 回答
1

是的,您需要创建一个事件并订阅它。遵循事件标准模式的一项建议:

enum ControlStatus {Idle, LoadingFile, ...}

class StatusChangedEventArgs : EventArgs
{
    public ControlStatus Status {get; private set;}

    public StatusChangedEventArgs(ControlStatus status)
        : base()
    {
        this.Status = status;
    }
}

partial class MyControl : UserControl
{
    public ControlStatus Status {get; private set;}

    public event EventHandler<StatusChangedEventArgs> StatusChanged;

    protected virtual void OnStatusChanged(StatusChangedEventArgs e)
    {
        var hand = StatusChanged;
        if(hand != null) hand(this, e);
    }

    void LoadFiles()
    {
        ...

        Status = ControlStatus.LoadingFiles; 
        OnStatusChanged(new StatusChangedEventArgs(this.Status));

        ...

        Status = ControlStatus.Idle; 
        OnStatusChanged(new StatusChangedEventArgs(this.Status));
    }
}

partial class MyHostWindowsForm : Form
{
    public MyHostWindowsForm()
    {
        var ctl = new MyControl();
        ...
        ctl.StatusChanged += ctl_StatusChanged;
    }

    void ctl_StatusChanged(object sender, StatusChangedEventArgs e)
    {
        switch(e.Status)
        {
            case ControlStatus.Idle:
                statusStripBar.Text = null;
                break;
            case ControlStatus.LoadingFiles:
                statusStripBar.Text = "Loading file(s)";
                break;
            ...
        }
    }
}
于 2012-08-29T19:53:42.440 回答