1

我有 2 个名为 UCCreateProfile.ascx(用于创建/编辑配置文件数据)和 UCProfileList.ascx(用于在 GridView 中显示配置文件数据)的用户控件。现在,每当创建新配置文件时,我都想更新我的 UCProfileList 控件以显示新条目。

针对上述问题的最佳解决方案是观察者模式。在我的例子中 UCCreatedProfile 是一个 Subject/Observable 并且 UCProfileList 是一个 Observer 并且根据观察者初始化时的模式定义,它知道谁是我的 Subject/Observable 并将自己添加到 Subject/Observable 列表中。因此,只要 Subject/Observable 发生更改,就会通知它。

这种模式最符合我的要求,但我在实现这个描述时遇到了一些问题,如下所示。

我在 CMS (Umbraco) 下工作,我没有任何物理容器页面 (.aspx)。我要做的是使用以下代码在 UCProfileList (Observer) onLoad 事件中找到 UCCreateProfile (Subject/Observable)。

private Control FindCreateProfileControl()
{
     Control control = null;
     Control frm = GetFormInstance();
     control = GetControlRecursive(frm.Controls);

      return control;
}

GetFormInstance() 方法在哪里

private Control GetFormInstance()
    {
        Control ctrl = this.Parent;
        while (true)
        {
            ctrl = ctrl.Parent;
            if (ctrl is HtmlForm)
            {
                break;
            }
        }
        return ctrl;
    }

和 GetControlRecursive() 方法是

 private Control GetControlRecursive(ControlCollection ctrls)
    {
        Control result = null;
        foreach (Control item in ctrls)
        {
            if (result != null) break;
            if (item is UCCreateProfile)
            {
                result = item;
                return result;
            }
            if (item.Controls != null)
                result = GetControlRecursive(item.Controls);
        }
        return result;
    }

这样我可以在 UCProfileList (Observer) 中找到 UCCreateProfile (Subject/Observable) 用户控件,但是找出 (Subject/Observable) 的方法不是那么快。如您所见,我需要遍历所有控件并首先找到 HtmlForm 控件,然后遍历 HtmlForm 控件下的所有子控件并找到我们正在寻找的适当控件。

其次,如果非常重要,将用户控件放置在容器中,我的代码只有在 UCProfileList.ascx(观察者)之前放置 UCCreatedProfile.ascx(主题/观察者)时才有效,因为这样 UCCreateProfile 将首先加载并在 UCProfileList 中查找。但是如果有人改变了这两个控件的位置,我的代码将无法工作。

因此,为了摆脱这些问题,我需要一些更快且独立于控件位置的解决方案。

我已经找到了一些解决方案,如下所述。请让我知道这是否是这样做的好方法。如果有替代方案,请告诉我。

我有一个会话级变量(带有 的字典Dictionary<ISubject, List<Observer>>)。无论首先初始化/加载哪个用户控件,用户控件都会将自己添加到此字典中。
如果先添加了 Subject/Observable,则会在这个字典中找到对应的观察者。
如果 Observer 首先添加,它将添加到具有空条目的字典中。添加主题后,就建立了关联。

问候,

/里兹万

4

1 回答 1

2

观察者模式最好通过事件和委托在 .NET 中实现。如果你使用事件和委托,Dictionary你提到的就变得完全没有必要了。例如,请参见下面的代码(仅显示重要部分):

public partial class UserProfile : System.Web.UI.UserControl
{
    //This is the event handler for when a user is updated on the UserProfile Control
    public event EventHandler<UserUpdatedEventArgs> UserUpdated;

    protected void btnUpdate_Click(object sender, EventArgs e)
    {
        //Do whatever you need above and then see who's subscribed to this event
        var userUpdated = UserUpdated;
        if (userUpdated != null)
        {
            //Initialize UserUpdatedEventArgs as you want. You can, for example,
            //pass a "User" object if you have one
            userUpdated(this,new UserUpdatedEventArgs({....}));
        }
    }
}

public class UserUpdatedEventArgs : EventArgs
{
    public User UserUpdated {get;set;}
    public UserUpdatedEventArgs (User u)
    {
        UserUpdated=u;
    }
}

现在从 上的控件订阅UserUpdated事件就像这样简单:UserProfileUserListControl

public partial class UserList : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //Find the UserProfile control in the page. It seems that you already have a 
        //recursive function that finds it. I wouldn't do that but that's for another topic...
        UserProfile up = this.Parent.FindControl("UserProfile1") as UserProfile;
        if(up!=null)
           //Register for the event
           up.UserUpdated += new EventHandler<UserUpdatedEventArgs>(up_UserUpdated);
    }

    //This will be called automatically every time a user is updated on the UserProfile control
    protected void up_UserUpdated(object sender, UserUpdatedEventArgs e)
    {
        User u = e.UserUpdated;
        //Do something with u...
    }
}
于 2012-09-04T14:21:31.567 回答