I have two ViewModels in my MVVM app. the one is bind to main window and another to popup window which appears after click on the button. in the popup window I need binding to the selected entity from main window. how can I access this entity in MainViewModel from PopupViewModel?
ZK has the concept of the event queue and global commands for communication between multiple ViewModels so we can use that to pass the current selected entity to the ViewModel of a popup window.
Using this zk mvvm demo page:
(see docs)
I added to the listbox a global command which fires out the current selected reminder of the main ViewModel which needs to be shown by a popup window:
<listbox id="list" multiple="true" rows="6"
model="#load(vm.reminders)"
selectedItem="#bind(vm.selectedReminder)"
onSelect="#global-command('refresh', reminder=vm.selectedReminder)">
Then I added to the bottom of the page a popup window with a second ViewModel:
<window id="info" visible="false" width="120px" border="normal" position="parent"
apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('org.zkforge.zktodo2.ui.ViewModelPopup')"
>
You have selected <label value="#load(vm.currentReminder.name)"/>
</window>
<button label="More info" onClick="info.doPopup()"/>
</zk>
The pop up Viewmodel has a method which accepts the global command which takes the entity as a parameter:
public class ViewModelPopup {
protected Reminder currentReminder = new Reminder();
public Reminder getCurrentReminder() {
return currentReminder;
}
public void setCurrentReminder(Reminder currentReminder) {
this.currentReminder = currentReminder;
}
#GlobalCommand #NotifyChange("currentReminder")
public void refresh(#BindingParam("reminder") Reminder reminder ){
this.setCurrentReminder(reminder);
return;
}
}
So now whenever you select an item in the listbox the refresh method is fired on the popup ViewModel passing into it data taken from the main ViewModel. Whenever you hit the "More info" button at the bottom of the page to show the popup window it displays the name of the current selected entity.
The documentation which I followed to do this is at:
(docs1)
(docs2)
The instructions to run that sample app are on the readme at (Docs3)
Do you have a list of entities in your mainwindow? if that is the case, from the view model of your main window you need to put your selected entity in a map and pass it as a param for createComponents just like this:
//In the view Model of the main window
Map arg = new HashMap();
arg.put("selectedEntity", SelectedEntity);
Executions.createComponents("/myPopup.zul", null, arg);
Now in the popup view model, you simply retrieve the value of your Entity in the Init method:
//PopupView model
#Init
public void init(#ExecutionArgParam("selectedEntity") SelectedEntity newEntity) {
entity = newEntity;
}
you can notice that the string in ExecutionArgParam is the key you put in the map.
Related
I'm adding a slider into my xamarin app, but im using view models to capture values. How can I move the slider on the GUI and show the value incrementing up and down and then capture its value?
or is there a way I can include the "MySlider_ValueChanged" event and apply it to the view model page rather than the content page code behind file?
is there a way I can include the "MySlider_ValueChanged" event and apply it to the view model page rather than the content page code behind file?
You have to find a BindableProperty which could be bound inside view model(ICommand) ,it should do the same work as the event ValueChanged .
For exmaple
We could handle Tapped event of TapGestureRecognizer in page code behind , we also could create new ICommand inside view model , and bind it with Command of TapGestureRecognizer .
However, Slider does not have command whose function is detecting the value changed , there is only DragStartedCommand and DragCompletedCommand ,
so the only solution is to trigger your method inside the setter method of Value .
Xaml
<Slider Value="{Binding CurrentProgress}" />
View Model
public double CurrentProgress
{
get { return currentProgress; }
set
{
currentProgress = value;
NotifyPropertyChanged("CurrentProgress");
YourMethod(value);
}
}
Refer https://stackoverflow.com/a/25141043/8187800.
This question stems from
How to disable or enable a MMenu (not MMenuItem) in an Eclipse E4 application
I have been attempting to grey-out/disable an entire Dynamic Menu Contribution in Eclipse 4 when a condition is met in the application. The Dynamic Menu Contribution is itself in the File Menu Model Element. My workaround has been to remove all options so the menu does not show anything, but is still active (not-grey) when the condition is met with the code below for clearing the menu.
items.clear();
if (checkMenuEnabled()) {
Fillthemenu();
}
This code below doesn't seem to disable the dynamic menu contribution like I want it to.
MenuImpl menu = (MenuImpl) modelService.find("menuID", application.getChildren().get(0).getMainMenu());
menu.setEnabled(checkMenuEnabled());
Here is an image of the model xmi UI items. The File->Submenu is what I am trying to grey out. Not the individual Dynamic Menu Contribution Items.
Model XMI
Thanks
So in your e4xmi file, you have a "Menu" with a "Dynamic Menu Contribution" and you want to gray out some items in the menu on some application condition, right?
The "Dynamic Menu Contribution" is attached to some "class", right?
In this class, when you generate a disabled "menu":
public class <the class referenced in e4xml> {
#Inject private EModelService modelService;
#AboutToShow
public void aboutToShow(List<MMenuElement> items, {...}) {
MDirectMenuItem dynamicItem = modelService.createModelElement(MDirectMenuItem.class);
dynamicItem.setLabel(<some label>);
dynamicItem.setIconURI(<some icon URI>);
dynamicItem.setContributorURI("platform:/plugin/platform:/plugin/<nom plugin>");
dynamicItem.setContributionURI(<menu item handler> "bundleclass://<plugin name>/<menu item handler class>");
--> dynamicItem.setEnabled(true/false); to enable/grey out the menu
--> dynamicItem.setvisible(true/false); to show/hide the menu
// add one or many MDirectMenuItems ...
items.add(dynamicItem);
}
}
In the menu item handler ("setContributionURI" class) where you implement the logic of the menu item, you can also show/hide/enable/disable the menu item:
public class <menu item handler class> {
#Execute
public void execute({...}) {
<code linked to the menu item selection here>
}
#CanExecute
public boolean canExecute(#Optional MMenuItem menuItem, {...}) {
// implement the logic to show/hide, enable/disable the menu item
menuItem.setVisible(true/false); // show/hide the menu item
return true/false; // enable/grey out the menu item
}
}
I am using the excellent Mvvmcross and Ninja Coder for Mvvmcross for building a cross platform app. For my windows store app I have created a view and a view model using Ninja coder. I have also created a UserControl which will be referenced in the view. Hence I need to bind the same viewmodel to the User control also. I have been trying to set the Data context of the user control to the singleton instance of viewmodel. I have set the data context of the user control like below.
public sealed partial class SearchResultsGridViewControl : UserControl
{
private SearchresultsViewModel _viewModel;
public SearchResultsGridViewControl()
{
this.InitializeComponent();
_viewModel = Mvx.IocConstruct<SearchresultsViewModel>();
this.DataContext = _viewModel;
}
}
But when I refer this User Control in my main view, it throws an error in XAML saying "Object Reference not set to an instance of an object. Cannot create an instance of SearchResultsGridViewControl".
This is my viewmodel:
public class SearchresultsViewModel : BaseViewModel
{
private ISearchResultsService _searchResultsService;
public SearchresultsViewModel(ISearchResultsService searchResultsService)
{
_searchResultsService = searchResultsService;
var items = _searchResultsService.DisplaySearchResults();
SchoolDetails = new ObservableCollection<School>(items);
}
private ObservableCollection<School> _schoolDetails;
public ObservableCollection<School> SchoolDetails
{
get { return _schoolDetails; }
set
{
_schoolDetails = value;
RaisePropertyChanged(() => SchoolDetails);
}
}
public ICommand RefineCommand
{
get
{
refineCommand = refineCommand ?? new MvxCommand(FilterSearchResultsBasedOnRefine);
return refineCommand;
}
}
public void FilterSearchResultsBasedOnRefine()
{
SchoolDetails = new ObservableCollection<School>(_searchResultsService.FilterSchoolsBasedOnRefine(MidDayMeals, PlayGround, DigitalClassroom, DayBoarding, TransportationFacility));
}
}
The grid view in my usercontrol is getting populated when it loads for the first time. But when RefineCommand is called to update the collection from the main view, the grid view in usercontrol is not getting updated. And I am guessing its because of that error earlier in setting the data context of the user control to view model. Please let me know what could be going wrong. I have been banging my head about it for days.
I've been using MVVMCross with Windows Store fairly recently. Without looking back at my code, I'm pretty sure that the Datacontext will inherit from it's parent unless overridden.
So as long as the MvxPage that you have presented has a viewmodel, any user control that you add to it, either in XAML or in code-behind, should share the same data context. If you are looking at doing some MVVMCross data-binding from the User Control, you should probably make sure your User Control implements IMvxStoreView, and ensure that the ViewModel property is set to the value of DataContext.
Hope that help.
Cheers,
Tristan
I think your first problem "Object Reference not set to an instance of an object" is a design time only issue - because you are trying to set the viewmodel using Mvx. at design time. You can workaround this issue if you want to by using design time viewmodels and possibly also by using one of the design time helpers (see https://github.com/MvvmCross/MvvmCross/blob/v3.1/CrossCore/Cirrious.CrossCore.Wpf/Platform/MvxDesignTimeHelper.cs).
I've no idea what your second problem is "The grid view in my usercontrol is getting populated when it loads for the first time. But when RefineCommand is called to update the collection from the main view, the grid view in usercontrol is not getting updated" - this sounds like an issue either in your xaml or in the results returned from FilterSearchResultsBasedOnRefine. From the current level of detail, I can't see what it is. My "gut feeling" is that the problem won't be MvvmCross specific - it'll just be a general Mvvm/data-binding issue.
Suppose I'm using the MVVM approach (Silverlight)
I'm having all my buttons handled with commands.
Suppose I have a button used to navigate to a certain page, say we selected a customer in a grid and want to navigate to the customer's details view.
Can I handle this button with a DelegateCommand? How? Can I handle the navigation from the ViewModel? Am I forced to handle the navigation from the code-behind.
Here we go:
Xaml:
<Button Command="{Binding GoToCustomerDetailsPage}" Content="Customer Details"/>
ViewModel:
private INavigationService _navigationService;
public ViewModel(INavigationService navigationService)
{
_navigationService=navigationService;
}
public ICommand GoToCustomerDetailsPage
{
get{
return new DelegateCommand(GoToCustDetailsPage,CanGoToCustDetailsPage);
}
}
private void GoToCustDetailsPage()
{
_navigationService.Navigate(new Uri("/CustomerDetails", UriKind.Relative));
}
private bool CanGoToCustDetailspage()
{
return true;//Or some sensible code that determines if this is sensible.
}
Basically, the Command is bound to the button as per normal. The command is a property on the viewmodel. When the Command is executed it simply calls a private method in the viewmodel.
here INavigationService not available.. It gives error if we add the namespace System.Windows.Navigation..
I have to bind my editor widget objects in property sheet.So that i can the property of my widget from property view.
Please help me on this, if possible provide me some code snippets.
You have a good example in the Getting started with Properties
Using the Properties view is simple enough.
Since it shows properties for the selected object, the first step to using it is to make sure that the workbench selection service knows about the object selected in your view. There’s an entire Eclipse Corner article written on the subject of the selection service
public void createPartControl(Composite parent) {
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
getSite().setSelectionProvider(viewer);
viewer.setInput(getViewSite());
}
Once you have your view contributing to the workbench selection, you need to make sure that the objects that your view is selecting contribute properties
(extract)
public class Person implements IPropertySource {
private String name;
private Object street;
private Object city;
public Person(String name) {
this.name = name;
this.street = "";
this.city = "";
}
public Object getEditableValue() {
return this;
}
public IPropertyDescriptor[] getPropertyDescriptors() {
return new IPropertyDescriptor[] {
new TextPropertyDescriptor("name", "Name"),
new TextPropertyDescriptor("street", "Street"),
new TextPropertyDescriptor("city", "City")
};
}
I indicated earlier that this solution is “not necessarily [the] most correct”. This is because, for this to work, my domain object needs to know about the very view-centric (and Eclipse-centric) notion of being a property source; in short, there is a tight-coupling between the model and view and this not a good thing™.
Using adapter is a better approach, as described in this article:
Person should implement IAdaptable.
See also this recent article on how to create a custom property view
how to hack the Properties View to listen only to a specific view.
The isImportant() method is the one which decides whether to create an IPage for the specific IWorkbenchPart or not.
The idea is to override that method and return false for all the workbenchPart that we are not interested in. Lets create the view first:
<view
class="com.eclipse_tips.views.CustomPropertiesView"
icon="icons/sample.gif"
id="com.eclipse-tips.views.customePropertiesView"
name="My Properties View">
</view>
The CustomPropertiesView should extend PropertySheet and override the isImportant():
public class CustomPropertiesView extends PropertySheet {
#Override
protected boolean isImportant(IWorkbenchPart part) {
if (part.getSite().getId().equals(IPageLayout.ID_PROJECT_EXPLORER))
return true;
return false;
}
}
In this case, I'm making the view only to respond to Project Explorer and ignore other views
According to this thread, the same principle should be valid for an Editor instead of a View.
The property sheet listens to the workbench page selection provider.
The selection provider depends on what viewer/editor is active.
Each editor/viewer provides their own selection provider to use when that editor/viewer is active.
This way the property sheet doesn't care who is active, it just listens to the selection provider.
That way depending upon the view, a different set of properties are displayed.
For example, the Navigator view provides IResource selections, so the property sheet then displays IResource properties when the Navigator is active.
The Workbench Selection mechanism is illustrated in this article
The ISelectionListener is a simple interface with just one method.
A typical implementation looks like this:
private ISelectionListener mylistener = new ISelectionListener() {
public void selectionChanged(IWorkbenchPart sourcepart, ISelection selection) {
if (sourcepart != MyView.this && // 1
selection instanceof IStructuredSelection) { // 2
doSomething(((IStructuredSelection) selection).toList()); // 3
}
}
};
Depending on your requirements your listener implementation probably needs to deal with the following issues as shown in the code snippet above:
In case we also provide selections (e.g. a view or editor) we should exclude our own selection events from processing. This avoids unexpected results when the user selects elements within our part (1).
Check whether we can handle this kind of selection (2).
Get the selected content from the selection and process it (3).