i learned how to implement my own SuggestionOracle("AuSuggestOracle") and own
Suggestions("AuMultiWordSuggestion"). In my case the suggestion object
is constructed with a DTO. On a selection event i need this dto (or
some fields of it) to react appropriate.
I implemented a widget containing 3 suggest boxes with this special
oracle and some logic between them. Now i want to apply MVP pattern -
split this widget in presenter and view.
At the moment the presenters display interface look like that:
public interface Display {
HasSelectionHandlers<Suggestion> getFedLand();
HasSelectionHandlers<Suggestion> getCounty();
HasSelectionHandlers<Suggestion> getCommunity();
AuSuggestOracle getFedLandOracle();
AuSuggestOracle getCountyOracle();
AuSuggestOracle getCommunityOracle();
void clearCounty();
void clearCommunity();
void activateForm();
Widget asWidget();
}
the problem is the implicit knowledge about my model in methods
returning "AuSuggestOracle". so my question is how to get the view/
interface "humble". in my case the displayed suggestion-strings are
ambiguous and i need at least the "id" of a selected item to know what
DTObject is selected.
The way I got around this is by leaving out the getters for the Oracle since once my presenter sets it my view doesn't need any information about it. So, my interface looked like this:
public interface Display {
...
void setSuggestionOracle(SuggestOracle oracle);
HasSelectionHandlers<SuggestOracle.Suggestion> getSelectionListener();
}
The problem I encountered was being able to add the suggestion to the SuggestBox after it was instantiated. To get around this, I initialized with a blank SuggestBox and then removed it from the view, updated in, and inserted it back into position.
After that, you can write your handler (in the presenter) to check if the suggestion is an instance of your custom suggestion and your presenter can handle the selection and push the relevant information back down to your view.
By doing this, all your view knows is that it will be taking generic suggestions for something, and that at some later time it will be updating with information (which will be as a result of the suggestion, but the view is to 'humble' to know that).
Related
First note that I am not referring to any specific framework or technology like XAML.
The question is how to implement the MvvM pattern using ICommand for selection of an item in a list (=clicking a row)?
I have a view model (pseudo code):
class ListViewModel
{
// Items in the list.
public ObservableCollection<T> Items {};
// Command for item selection.
public ICommand ItemSelectedCommand
{
...
}
// Select an item in the list.
public void SelectItem(int index)
{
...
}
// The current selected item.
public T SelectedItem
{
get { ... };
}
}
How would I now connect my UI to that view model "manually"? Say, for instance in an iOS application.
I would probably have a UITableViewController, get an instance of the view model and populate the UITableView contents from it. Then I would trigger the ICommand from the RowSelected() method.
And here comes the thing I don't understand: how does the view model now know which item index was selected? I don't want to call SelectItem() because then I would not need the loosely coupled ICommand at all.
And maybe here we have to look how it is solved in XAML to understand the trick?
Coming from XAML and WPF, there are two options to forward selection changes from the UI to the ViewModel (as I understand your question, you're not asking about the other way around - feedbacking changes in the ViewModel to the UI - here):
Command with payload
The ICommands Execute method has a payload parameter. Executing a command without a payload can be done passing null:
SomeCommand.Execute(null);
In your case, it would make sense to pass the selected item as the parameter in the event handler:
vm.ItemSelectedCommand.Execute(eventArgs.SelectedItem);
or
vm.ItemSelectedCommand.Execute(myList.SelectedItem);
In the command's execution method, you can handle the parameter. Note that your ViewModel property SelectedItem is not directly involved here. If you need the selected index explicitly (which is not the case, usually), I would check the selected item's index in the Items collection.
Binding selected item of list to a ViewModel property
Option B is to 'bind' the selected item of the list to a distinct property on the ViewModel, in your case the SelectedItem property in the event handler of the list:
vm.SelectedItem = myList.SelectedItem;
The command is kind of redundant then, although you could invoke it without a payload after setting SelectedItem on the ViewModel. I would rather handle the change of the selected item in the set accessor of the property on the ViewModel.
Note: XAML and WPF come with quite a lot of infrastructure code out of the box. MVVM doesn't make sense without a proper framework to actually take care of binding UI and ViewModels in a loosely coupled way. You quickly end up with a lot of extra work and little benefit, because you're still maintaining tight dependencies. Bottom line: I recommend getting or writing a proper MVVM framework, before actually implementing it.
On my first project trying out Caliburn.Micro, I like a lot of the things :-)
One thing I miss (or havn't discovered yet) is how to separate the viewmodel and a command.
CM doesn't support ICommand, as it's way of doing things is superior. I'm sure it's true, so I would love a small push in the right direction to achieve this or perhaps discover a better way.
As I understand you have to put the "Execute" method and "CanExecute" property directly in the viewmodel, named to match the control in the view, to get the magic to work.
I would like to put the "Execute" and "CanExecute" in a different object that is property on the viewmodel and then CM would automatically bind to that object, using the control name and property names as usually.
Repost from the forum on Caliburn Micro, I didn't get any answers so I'm trying my luck here.
You should try to avoid invalidating the Law of Demeter. Therefore, on your view model you can have an execute method, and a CanExecute property (usually calculated), and these can call into the containing model where appropriate, e.g:
public void Save
{
// .. save logic
}
public bool CanSave
{
get
{
return this.model.CanSave ... and other logic etc.
}
}
You must remember to notify a change in the calculated property when the can save state changes, e.g:
public void CodeThatGetsRunWhenAPropertyOfTheModelChanges()
{
this.NotifyOfPropertyChanged(() => this.CanSave);
}
If you have e.g. a Button on your view with x:Name="Save", then Caliburn.Micro will automatically invoke your Save verb on the view model when the button is clicked, and will automatically enable and disable the button when the CanSave property value changes.
To avoid fat ViewModels you also need to avoid fat Views. Caliburn.Micro allows you to compose Views/ViewModels as described in Screens, Conductors and Composition.
The short version is, you can include a "DetailView" and "DetailViewModel" pair in a "MasterView"/"MasterViewModel" shell by defining a DetailViewModel-typed property in MasterViewModel and adding a ContentControl named after it in MasterView. Binding and actions work as usual, so you avoid both fat models/views and routing of commands.
Another option is to bind a MasterView element to a DetailViewModel property or action, by prepending the detail's property to the target's name. I can't find the specific URL yet, so the example is from memory.
Assuming you have the following classes:
public class MasterViewModel:Screen
{
public property DetailViewModel MyDetails{get;set;}
}
and
public class DetailViewModel:Screen
{
public property string SomeText{get;set;}
public void DoTheBoogie(){}
}
You can add a control in you MasterView named 'MyDetails_SomeText' to bind to the DetailViewModel.SomeText. You can also bind to DoTheBoogie the same way.
I prefer to create a separate View though, named DetailView and add a ContentControl named "MyDetails" in MasterView. This results in a cleaner and more modular design
I am currently implementing an Eclipse-Plugin which is using the standard properties view, connected to a Navigator. It also features a textual editor, which is able to connect regions within its' document to certain objects that can supply properties to the PropertiesView (i.e. the same objects, that are displayed in the Navigator).
However, the Tuturials I found only dealt with Views that used a pre-implemented Viewer, which already supported passing on the selected element to the Properties View.
The TextEditor does not do that (I am using jface and a subclass of the AbstractTextEditor class), because it's SelectionProvider returns informations about the offset and the length of the selection only.
How do I have to modify the SelectionProvider of my TextEditor, such that it provides information usable to the Properties View?
Thank you in advance
Okay, I have managed to find the solution myself.
First of all, I had to implement the getAdapter() method in my subclass of TextEditor such that it returns an Adapter for IPropertySourceProvider, that can deal with the type of elements that are selected in my AbstractTextEditor.
Then, I implemented an ISelection that extended TextSelection, in order to not interfere with any selection-specific mechanism supplied by the AbstractTextEditor, and implements the interface IStructuredSelection, because the Properties View works with this interface of ISelection only.
An IStructuredSelection features basic methods of an array, however, in my case it is only possible to ever select only a single element, so implementation of these methods were trivial.
The last step was to get my ISelection to the right place. Overwriting the getSelection()-method of the ISelectionProvider of the AbstractTextEditor did not suffice, because obviously, the methods of firing SelectionChangedEvents does not use this method.
Thus, instead of using a standard SourceViewer, I used my own implementation in which I basically overrid the methods fireSelectionChanged(int offset, int length) and firePostSelectionChanged(int offset, int lenght), such that they use events containing my ISelection.
The rest is implementing the handling of my Objects in the Adapter for IPropertySourceProvider in a way that it returns an IPropertySource for the given Object, as it is shown in various tutorials.
In the "Admin" area of my application, an object must be available in ViewData on every page (for display in the Master template). I have already inherited from Controller, so I cannot make a simple base class that handles it. What is a good solution of doing this when not using inheritance? An ActionFilter seems interesting but I don't want to put it on every controller in the Admin area. I'm considering the following:
Custom ControllerFactory that detects Area as well
Application_BeginRequest(), though I have no knowledge on executing controller then.
Maybe you have a better solution?
In this case I would create a separate action that executes a partial view that shows the data you need. In my opinion this is the most clean solution for this kind of problem and it's easily testable and reusable.
i have a dropdown on my masterpage. you dont need viewdata for it. i did it like this
code on masterpage:
<%= Html.DropDownList("schselectr", MVC2_NASTEST.MvcApplication.masterSchooljaarList())%>
in Global.asax.cs
public static SelectList masterSchooljaarList() {
NASDataContext _db = new NASDataContext();
List<Schooljaar> newlist = _db.Schooljaars.ToList();
return new SelectList(_db.Schooljaars.ToList(), "Sch_Schooljaar", "Sch_Schooljaar");
}
so simply, it calls the method, which returns the data i need, every time you load the page. easy, clean, effective.
When working with MVP in GWT how would you work with a table? For example if you had a table of users does your view look like this?
public interface MyDisplay{
HasValue<User> users();
}
or would it be more like this?
public interface MyDisplay{
HasValue<TableRow> rows();
}
MVP makes a ton of sense until you start dealing with widgets that need to display lists of non-primitive data. Can anybody shed some light?
This mailing list archive appears to ask the same question but never reaches a solid resolution...
http://www.mail-archive.com/google-web-toolkit#googlegroups.com/msg24546.html
HasValue<User> or HasValue<TableRow> would not work in this case, because this would only permit handling a single row.
You could maybe use a HasValue<List<User>> but that would mean, that your view has to render the entire table on each change.
I might be wrong, but I think for tables its best to use a Supervising Presenter instead of the Passive View.
Have a look at the PagingScrollTable widget in the GWT Incubator:
public class PagingScrollTable<RowType> extends AbstractScrollTable implements
HasTableDefinition<RowType>, ... {
...
TableModel<RowType> getTableModel()
...
}
For a PagingScrollTable, a MutableTableModel<RowType> is used as implementation of TableModel<RowType>.
MutableTableModel<RowType> in turn implements the following interfaces:
HasRowCountChangeHandlers, HasRowInsertionHandlers, HasRowRemovalHandlers, HasRowValueChangeHandlers<RowType>
The PagingScrollTable registers itself as listener on the MutableTableModel and therefore gets very fine-grained notifications of updates. The resulting implementation should be very performant.
this discussion does reach a resolution for similar question:
http://groups.google.com/group/google-web-toolkit/browse_thread/thread/4887a7565d05f349?tvc=2
This might be a very interesting blog post:
http://www.draconianoverlord.com/2010/03/31/gwt-mvp-tables.html