Passing values between views

Topics: CAB & Smart Client Software Factory
Mar 20, 2007 at 5:31 PM
Hi,
I have a view where user selects the OrderNumber and clicks on Details button.
I have an OrderDetails view which is subscribed to the orderdetails event.
This how I have coded this in the Orderdetails-Presenter

public string strTextBox;
EventSubscription(EventTopicNames.OnOrderDetails, ThreadOption.UserInterface)
public void OnOnOrderDetails(object sender, EventArgs<String> eventArgs)
{
strTextBox = eventArgs.Data.ToString();
}

Orderdetails-View
protected override void OnLoad(EventArgs e)
{
_presenter.OnViewReady();
}

But I am unable to access the value for the Ordernumber in this view.
Please let me know how do I do it.
Thanks.
Mar 20, 2007 at 5:37 PM
Why dont you create your Own EventArgs<TypeOrder> and on that eventsubscriber cast the EventArgs to EventArgs<TypeOrder>.

That way you can access the data.
Mar 20, 2007 at 5:40 PM
Can you explain it in a detailed manner?
Mar 20, 2007 at 6:07 PM
public class MyEventArgs : EventArgs
{
public MyEventArgs()
{
}

//My properties
//My methods
}

EventPublication(EventTopicNames.DetailClick, PublicationScope.Descendants)
public event EventHandler<MyEventArgs> DetailClick;

EventSubscription(EventTopicNames.DetailClick, Thread = ThreadOption.UserInterface)
public void DetailClick(object sender, MyEventArgs e)
{
}

Then you just call the handler

this.TaskListUpdating(this, new MyEventArgs())
Mar 20, 2007 at 6:18 PM
Currently,
I have subscribed to the Orderdetails event in my Module Controller.
Is it the right way?

If so,
How do I access the everntargs in the view?
Mar 20, 2007 at 7:55 PM

bsatyen wrote:
Currently,
I have subscribed to the Orderdetails event in my Module Controller.
Is it the right way?

If so,
How do I access the everntargs in the view?


Your presenters are the classes that should be communicating via EventBroker events. Otherwise you are not making use of the MVP/MVC pattern.


This is how I would do it (given that you have two views, OrderNumberView and OrderDetailsView):

(1) When the user clicks the OrderDetails button on the OrderNumberView (after selecting an OrderNumber) the view calls the presenter. Like this:

_presenter.OrderSelected(_textBox.Text);

(2) The Presenter is then charged with firing an event:

[EventPublication(EventTopicNames.OrderSelected, PublicationScope.Descendants)]
public event EventHandler<EventArgs<string>> OnOrderSelected;
 
public void OrderSelected(string orderNumber)
{
    if(OnOrderSelected != null)
        OnOrderSelected(this, new EventArgs<string>(orderNumber);
}

(3) The OrderDetailsViewPresenter then listens for the event and does whatever it needs to do to update the OrderDetailsView:

[EventSubscription(EventTopicNames.OrderSelected, Thread = ThreadOption.UserInterface)]
public void OrderSelected(object sender, EventArgs<string> e)
{
    OrderDetails details = _myOrderService.GetDetails(e.Data);
    View.UpdateView(details); 
}


The CAB (if you are using SCSF) has a generic EventArgs<T> class that you can use to pass specific types of data around.
Mar 20, 2007 at 8:53 PM
If that is the case,
how do my button click will open the orderdetails view....without using
WorkItem.WorkspacesConstants.WorkspaceNames.RightWorkspace.Show(view);
in the module controller for these views..
Mar 20, 2007 at 11:47 PM

bsatyen wrote:
If that is the case,
how do my button click will open the orderdetails view....without using
WorkItem.WorkspacesConstants.WorkspaceNames.RightWorkspace.Show(view);
in the module controller for these views..



Well, it might be better to wrap this functionality in a WorkItem of its own instead of the ModuleController. Generally, we use the ModuleController in a very focused, simple way: it creates WorkItems and calls Run(). It's up to those WorkItems to handle the showing of views, creation of toolstrip items, and listening for events.

If you try and do everything in the ModuleController I think you'll soon find it becomes a bloated and difficult to maintain class.

Mar 24, 2007 at 6:51 AM
Edited Mar 24, 2007 at 6:52 AM
Chris wrote: "Generally, we use the ModuleController in a very focused, simple way: it creates WorkItems and calls Run()."

I currently use ModuleController to wrap functionality. Just for fun I decided to use it to create WorkItems like Chris, but I am not having any luck. I used the Bank Branch SCSF example and an older CAB example to get me started. In ModuleController I have this line of code:

ControlledWorkItem<ReportWorkItem> workItem1 = WorkItem.WorkItems.AddNew<ControlledWorkItem<ReportWorkItem>>("1");

In the ReportWorkItem class I then try to make use of WorkItem, but it is null.

Any thoughts on why WorkItem is null?

- Rich
Mar 24, 2007 at 10:43 AM
Create a Controller Class
    class ReportViewController : WorkItemController
    {
        private ReportView reportView = null;
 
        public override void Run()
        {
            base.Run();
            if (reportView == null)
                reportView = WorkItem.SmartParts.AddNew<ReportView>();
        }
 
        public void Activate()
        {
            WorkItem.Workspaces[Constants.WorkspaceNames.RightWorkspace].Show(reportView);
        }
    }

Then in your ModuleController or some presenter class
        private void ShowReportView()
        {
            const string workItemID = "ReportViewController";
            ControlledWorkItem<ReportViewController> workItem;
            if (!this.WorkItem.WorkItems.Contains(workItemID))
            {
                workItem = this.WorkItem.WorkItems.AddNew<ControlledWorkItem<ReportViewController>>(workItemID);
                workItem.Controller.Run();
            }
            else
            {
                workItem = WorkItem.WorkItems[workItemID] as ControlledWorkItem<ReportViewController>;
            }
            workItem.Controller.Activate();
        }
Mar 24, 2007 at 2:24 PM

raohara wrote:
Chris wrote: "Generally, we use the ModuleController in a very focused, simple way: it creates WorkItems and calls Run()."

I currently use ModuleController to wrap functionality. Just for fun I decided to use it to create WorkItems like Chris, but I am not having any luck. I used the Bank Branch SCSF example and an older CAB example to get me started. In ModuleController I have this line of code:

ControlledWorkItem<ReportWorkItem> workItem1 = WorkItem.WorkItems.AddNew<ControlledWorkItem<ReportWorkItem>>("1");

In the ReportWorkItem class I then try to make use of WorkItem, but it is null.

Any thoughts on why WorkItem is null?

- Rich


I should clarify this a bit. We don't use the WorkItemController base class. After we generate the ModuleController class in SCSF (during creation of a new module) we change the base class to a plain old WorkItem. Then, in the Module class we just add it like a normal WorkItem and call Run().

public override void Load()
{
    base.Load();
 
    WorkItem workItem = _rootWorkItem.WorkItems.AddNew<ModuleController>();
    workItem.Run();
}

We keep the class named ModuleController, because we feel that best fits the description of that class and its responsibilities.

We view the WorkItemController and the ControlledWorkItem classes as an unnecessary layer of indirection that complicates the app design. By sticking with the WorkItem class as the base class for our ModuleController we're able to work with it exactly like any other WorkItem in the hierarchy of objects. It's just less confusion.
Mar 26, 2007 at 3:02 PM
Allan - thanks for the code sample. Using it I was able to pinpoint my problem and I made great progress over the weekend.

Chris - I appreciate the comment about the indirection issue. Before I posted my question I tried to figure out why the examples and the framework generated code don't use the WorkItem class. I couldn't, but being new to SCSF and CAB I figured there was a reason that I couldn't see so I just left things as they are. Your comment makes me realize I was not that far off in considering using the WorkItem class instead of WorkItemController and ControlledWorkItem.

- Rich

P.S. Go Hawks!