connect two widget instance

Jun 10, 2008 at 4:00 PM
I would read a value of Gridview Item selected content in a .ascx content in a widget by an other .ascx content in an other widget instance.
How can I do?

Thank you.
Jun 17, 2008 at 4:25 PM
Hi Germon,

I've managed to create a simple communication link between widgets by implementing 2 custom interfaces - IProvider and ISubscriber.

IProvider:

   void Attach(ISubscriber subscriber);
   void Detach(ISubscriber subscriber);

ISubscriber:

   void Update(ActionListItem listitem);

Simple example that uses the two providers:


ActionListItem class:

   public string Name
    {
        get;
        set;
    }

ActionListItemService class:

 public static List<ActionListItem> GetListItems()
    {

        List<ActionListItem> items = new List<ActionListItem>();
        for (int i = 1; i < 11; i++)
        {
            ActionListItem item = new ActionListItem();
            item.Name = "List Item " + i;

            items.Add(item);

        }
        return items;
    }

ActionListWidget:

<asp:Panel ID="SettingsPanel" runat="server" Visible="false">
    <asp:Label ID="lblNoSettings" runat="server" />
    <br />
    <br />
</asp:Panel>
<asp:ObjectDataSource ID="ActionListData" runat="server" DataObjectTypeName="ActionListItem"
    TypeName="ActionListItemService" SelectMethod="GetListItems" />
<asp:DataList ID="ActionList" runat="server" DataSourceID="ActionListData" OnItemDataBound="ActionList_ItemDataBound">
    <ItemTemplate>
        <div>
            <asp:LinkButton ID="ActionLink" runat="server" OnCommand="ActionLink_Command" />
        </div>
    </ItemTemplate>
</asp:DataList>

Codebehind - remember to implement the IProvider:

private IWidgetHost _Host;
    List<ISubscriber> subscribers = new List<ISubscriber>();

    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void ActionList_ItemDataBound(object sender, DataListItemEventArgs e)
    {
        if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
        {
            ActionListItem item = (ActionListItem)e.Item.DataItem;

            LinkButton lb = (LinkButton)e.Item.FindControl("ActionLink");
            lb.CommandArgument = item.Name;
            lb.Text = item.Name;
        }
    }

    protected void ActionLink_Command(object sender, CommandEventArgs e)
    {

        foreach (ActionListItem item in ActionListData.Select())
        {

            if (item.Name == e.CommandArgument.ToString())
            {
                Notify(item);
                break;
            }

        }
    }

    private void Notify(ActionListItem item)
    {
        foreach (ISubscriber subscriber in subscribers)
        {
            subscriber.Update(item);
        }

    }

    #region IProvider Members

    public void Attach(ISubscriber subscriber)
    {
        subscribers.Add(subscriber);
    }

    public void Detach(ISubscriber subscriber)
    {
        subscribers.Remove(subscriber);
    }

    #endregion

    #region IWidget Members

    void IWidget.Init(IWidgetHost host)
    {
        this._Host = host;
    }

    void IWidget.ShowSettings()
    {
        SettingsPanel.Visible = true;
 
    }
    void IWidget.HideSettings()
    {
        SettingsPanel.Visible = false;
    }
    void IWidget.Minimized()
    {
    }
    void IWidget.Maximized()
    {
    }
    void IWidget.Closed()
    {
    }

    #endregion

ActionListDetailsWidget:
<asp:Panel ID="SettingsPanel" runat="server" Visible="false">
<asp:Label ID="lblNoSettings" runat="server" />
<br /><br />
</asp:Panel>
<asp:Label ID="Label1" runat="server"></asp:Label>

Code behind - remember to implement ISubscriber:

private IWidgetHost _Host;
    protected void Page_Load(object sender, EventArgs e)
    {
        Label1.Text = Label;
    }

    private XElement _State;
    private XElement State
    {
        get
        {
            if (_State == null) _State = XElement.Parse(this._Host.GetState());
            return _State;
        }
    }

    public string Label
    {
        get { return State.Element("label").Value; }
        set { State.Element("label").Value = value; }
    }

    private void SaveState()
    {
        var xml = this.State.Xml();
        this._Host.SaveState(xml);
    }

    #region ISubscriber Members

    public void Update(ActionListItem listitem)
    {
        Label = listitem.Name;
        Label1.Text = Label;
        SaveState();
    }

    #endregion

    #region IWidget Members

    void IWidget.Init(IWidgetHost host)
    {
        this._Host = host;
    }

    void IWidget.ShowSettings()
    {
        SettingsPanel.Visible = true;
    }
    void IWidget.HideSettings()
    {
        SettingsPanel.Visible = false;
    }
    void IWidget.Minimized()
    {
    }
    void IWidget.Maximized()
    {
    }
    void IWidget.Closed()
    {
    }


    #endregion

In the default.aspx page:

Create the following method:

    protected void RefreshSubscribers()
    {

        var columnPanels = new Panel[] { 
            this.FindControl("LeftPanel") as Panel, 
    this.FindControl("MiddlePanel") as Panel,
            this.FindControl("RightPanel") as Panel };

        IProvider provider = null;

        foreach (Panel panel in columnPanels)
        {
            foreach (WidgetContainer instance in panel.Controls.OfType<WidgetContainer>())
            {
                WidgetInstance widget = (WidgetInstance)instance.WidgetInstance;
                if (widget.Title == "Action List")
                {
                    provider = instance.ActionListProvider;
                }
            }
        }
        foreach (Panel panel in columnPanels)
        {
            foreach (WidgetContainer instance in panel.Controls.OfType<WidgetContainer>())
            {
                WidgetInstance widget = (WidgetInstance)instance.WidgetInstance;
                if (widget.Title == "Action List Details")
                {
                    if (instance.ActionListSubscriber != null)
                    {
                        ISubscriber subscriber = instance.ActionListSubscriber;
                        provider.Attach(subscriber);
                        RefreshAllColumns();
                    }
                }
            }
        }
    }

Call this method in the Page_Load event.

WidgetContainer.ascx:

Add the following properties to this user control:

    public IProvider ActionListProvider
    {
        get;
        set;
    }
    public ISubscriber ActionListSubscriber
    {
        get;
        set;
    }

Add the following code at the end of the OnInit method in WidgetContainer.ascx:

 try
        {
            this.ActionListProvider = widget as IProvider;
        }
        catch (Exception ex)
        {
            //do nothing - unable to cast widget
        }

        try
        {
            this.ActionListSubscriber = widget as ISubscriber;
        }
        catch (Exception ex)
        {
            //do nothing -  unable to cast widget
        }


Hope this helps you get started.  The code could be easily improved - but shows that connecting widgets together is possible.

Regards,

Peter


Oct 22, 2008 at 4:27 AM
Thanks very much for that code. This works great for me except I made some changes for it to work without errors. I am adding it here so that it will be helpful for others.

1. replaced this part of code with.
-------------------------
        var columnPanels = new Panel[] { 
            this.FindControl("LeftPanel") as Panel, 
    this.FindControl("MiddlePanel") as Panel,
            this.FindControl("RightPanel") as Panel };

this one
------------------------
var columnPanels = new Panel[] {

 

this.WidgetPanelsLayout.FindControl("LeftPanel") as Panel,

 

 

this.WidgetPanelsLayout.FindControl("MiddlePanel") as Panel,

 

 

this.WidgetPanelsLayout.FindControl("RightPanel") as Panel };


2. When registering ActionListDetailsWidget we need to add <state><label></label></state> under State column i fnot it will throw null reference exception.

Rest of the code is perfect. Now I am using this code basis to update a graph dynamically from my pivot table.

Thanks,
Kiran

 

Oct 24, 2008 at 1:14 PM
I am adding a .NET standard Event system that will be released soon. Idea is widgets will subscribe to global events like OnAddWidget, OnDeleteWidget, OnWidgetEvent(sender, data). Whenever some widget wants to raise an event so that other widgets can consume it and do something, it will raise OnWidgetEvent( this, new MyEventArgs(...)). Other widgets will get notification from this event and do whatever they like. This will give a nice loosly couple arhcitecture for widget to widget data exchange.
Feb 6, 2009 at 3:57 AM
Any chance to see it in V 1.8  or whatever next release ,  whenever it is released ? 

Feb 8, 2009 at 6:51 AM
I would also like to hear about this addition's availability.
Jan 28, 2011 at 5:18 PM

this is rather new, i wonder if anyone of you still be updating on this,

there is a master and child communication in the widget folder, which works.

 

I wonder, are you able to communicate from outside of the widget with the widget.

I.e add a button in the header or the "Add Stuff" panel to trigger some value inside "one" of the widget or all the widget ..