Why isn't MvxStandardTableViewSource SelectedItem updating properly? - xamarin.ios

I'm trying to bind a UITableView to an ObservableCollection<MyTypeViewModel> using MvxStandardTableViewSource, and I'm getting weird behavior and bindings that aren't working
The (partial) code is this:
tblFeatures = new UITableView ();
mSource = new MvxStandardTableViewSource(tblFeatures, "TitleText Name");
var set = this.CreateBindingSet<MyTypeView, MyTypeViewModel> ();
set.Bind(mSource).To (vm => vm.Objects);
set.Bind(mSource).For(s => s.SelectedItem).To (vm => vm.SelectedObject);
set.Apply ();
What I'm seeing is that when I select an item in the table, it does update SelectedObject with the new value. But when I change SelectedObject by some other means, the table does not update the displayed selected item. I have verified that the SelectedObject really is being changed, by setting a breakpoint and by binding another control to it; the other control (a label) does change as the selection changes, but the UITableView does not.
Am I doing something wrong, or could this be an issue in MVVMCross?

The selecteditem binding was requested as a 'nice to have' and was mainly requested for the user story where a user clicks on a list item - so this is currently a 'one way to source' implementation.
The very basic details and some code can be found via - https://github.com/slodge/MvvmCross/issues/278
In truth, the current binding is abusing the 'selected' paradigm - as it doesn't really reflect the selection state of the cell and also has no handling of mutiselect - instead it just lets the viewmodel know the latest tapped item.
If there are genuine user stories/requirements for full two'way binding, then these should be addable - eg if the user story were for scrolling the item into view then 'scrollToRowAt' could be used - see How to scroll UITableView to specific position - but this again might not be true 'selection' within the uitableview.
if you wanted to implement this yourself it should be fairly straight-forward to override the binding with your own one (see the custom binding n+1 in http://mvvmcross.wordpress.com for an intro on custom bindings).
could this be an issue in MVVMCross?
Overall I think I'd categorise it as a known limitation of that particular binding caused by lack of user demand and by some confusion over whether selection genuinely means selection in the touch screen era.
if it was logged as a bug I'd say it wasn't.. If it was logged ss a feature request I'd try getting as much user input as i could about what devs really want from this, whether they want true cell selection or scroll into view, both or something more.

By other means you mean not from UI thread I presume. Please try by invoking the change on UI thread.

Related

Kentico 9: Auto Add Binding in Custom Module

I have created a custom module (actually I have created a handful in recent years, and this same obstacle frustrates me every time) following the Kentico documentation:
https://docs.kentico.com/display/K9/Creating+custom+modules
The problem I end up with every time, is in developing the User Interface for Parent/Child classes. I create a Vertical Tab node, and beneath it I add an edit tab and a Binding tab for the child class. This all works, and I can add and remove bindings at will, but what I can't do is ADD a new child class and bind it.
Using the Standard Edit Binding template, I am able to bind EXISTING Job Titles to the selected Category, but I cannot CREATE a new one from that page:
To solve this, I created a custom Edit Binding template, and added a New Child Class Header Action that points to a New / Edit Object child:
Which gives me a button that I can use to add a new child class (Job Title):
This approach works per se, in that I can click the New Job Title button and create a new item on the subsequent page:
But no binding is created to link the child object (Job Title) to the selected parent object (Category), An even bigger problem is that once I click Save, I am presented with the following:
The new object DOES SAVE, but the post-save navigation is somehow failing. The event log offers little in the way of diagnostics:
So I thought to create a completely custom interface to accomplish my needs here, according to the Kentico documentation:
https://docs.kentico.com/display/K9/Manually+creating+the+interface+for+custom+modules
So I change the Element Content of the New Job Title page to a custom page that I created to post a DataForm for the new object:
Taking care to assign the proper Object Types on the Properties Tab:
The intent was to programmatically create the binding upon save and also handle the correct navigation to avoid the ambiguous parameter error above, but when this page loads, the UIContext.ObjectID and UIContext.ParentObjectID are both 0:
So I cannot create the binding programmatically. I was able however to solve the error that I received by manually assigning the redirect. The experience is still lacking even with this hack, since it returns to the listing page, but the user still has to click "Add Items" to assign the binding after successfully creating it with the custom page I built.
This cannot be the proper way to do this, so any help with getting me on the right track would be greatly appreciated.
In order for the EditedObject to have a value you have to either decorate the page with the EditedObjectAtribute e.g. like this:
[EditedObject("<custom.objecttype>", "<objectid>", ...)]
or set the object yourself:
int objectId = QueryHelper.GetInteger("objectid", 0);
EditedObject = SomeInfoProvider.GetSomeInfo(objectId);
In your case, I'd recommend exploring what query parameters are available on the page and using them to fetch appropriate object(s). Also, make sure "JobCategoryId" is passed to the "New Job Title" dialog so that you can create the binding.
Btw - kudos for well asked question!

OrchardCMS: How to access Content Menu Item boolean field in cshtml view

In orchard, I've added a boolean field called "IsDone" to the built in Content Menu Item content part via that Admin interface. I've then picked an item in Navigation and set the option to "yes" for the corresponding field i added.
In my custom theme, I've copied over MenuItem.cshtml.
How would I get the value of my custom "IsDone" field here?
I've tried something like
dynamic item = Model.ContentItem;
var myValue = item.MenuItem.IsDone.Value;
but I'm pretty sure my syntax is incorrect (because i get null binding errors at runtime).
thanks in advance!
First i suggest you use the shape alternate MenuItemLink-ContentMenuItem.cshtml instead of MenuItem.cshtml to target the content menu item directly.
Secondly, the field is attached to the ContentPart of the menu item. The following code retrieves the boolean field from this content part:
#using Orchard.ContentManagement;
#using System.Linq;
#{
Orchard.ContentManagement.ContentItem lContentItem = Model.Content.ContentItem;
var lBooleanField = lContentItem
.Parts
.Where(p => p.PartDefinition.Name == "ContentMenuItem") // *1
.SelectMany(p => p.Fields.Where(f => f.Name == "IsDone"))
.FirstOrDefault() as Orchard.Fields.Fields.BooleanField;
if (lBooleanField != null)
{
bool? v = lBooleanField.Value;
if (v.HasValue)
{
if (v.Value)
{
#("done")
}
else
{
#("not done")
}
}
else
{
#("not done")
}
}
}
*1
Sadly you cannot simply write lContentItem.As<Orchard.ContentManagement.ContentPart>() here as the first part in the part list is derived from this type, thus you would receive the wrong part.
While #ViRuSTriNiTy's answer is probably correct, it doesn't take advantage of the power of the dynamic objects that Orchard provides.
This is working for me but is a much shorter version:
#Model.Text
#{
bool? IsDone = Model.Content.ContentMenuItem.IsDone.Value;
var IsItDoneThough = (IsDone.HasValue ? IsDone.Value : false);
}
<p>Is it done? #IsItDoneThough</p>
You can see that in the first line I pull in the IsDone field using the dynamic nature of the Model.
For some reason (I'm sure there is a good one somewhere) the BooleanField uses a bool? as its backing value. This means that if you create the new menu item and just leave the checkbox blank it will be null when you query it. After you have saved it as checked it will be true and then if you go back and uncheck it then it will have the value false.
The second line that I've provided IsItDoneThough checks if it has a value yet. If it does then it uses that, otherwise it assumes it to be false.
Shape Alternate
#ViRuSTriNiTy's other advice, to change it to use the MenuItemLink-ContentMenuItem.cshtml instead of MenuItem.cshtml is also important.
The field doesn't exist on other menu items so it will crash if you try to access it. Just rename the .cshtml file to fix this.
Dynamic Model
Just to wrap this up with a little bit of insight as to how I got there (I'm still learning this as well) the way I figured it out is as follows:
.Content is a way of casting the current content item to dynamic, so you can use the dynamic advantages with the rest of line;
When you add the field in the admin panel it looks like it should be right there on the ContentItem, however it actually creates an invisible ContentPart to contain them and calls it whatever the ContentItem's type is.
So if you had added this field to a Page content type you would have used Model.Content.Page.IsDone.Value. If you had made a new content type called banana it would be Model.Content.Banana.IsDone.Value, etc.
Once you are inside the "invisible" part which holds the fields you can finally get at IsDone. This won't give you the actual value yet though. Each Field has its own properties which you can look up in the source code. the IsDone is actually a BooleanField and it exposes its data via the Value property.
Try doing a solution-wide search for : ContentField to see the classes for each of the fields you have available.
Hopefully this will have explained things clearly but I have actually written about using fields in a blog post and as part of my getting started with modules course over on the official docs (its way down in part 3 if you're curious).
Using built-in features instead of IsDone
This seems like a strange approach to do it this way. If you have a Content Item like a Page then you can just use the "Show on a menu" setting on the page.
Go to admin > content > open the page > down near the bottom you will find "Show on a menu":
This will automatically put it into your navigation and then you can move it around to where you want:
After it "IsDone" you can just go back and untick the "Show on a menu" option.
Setting up the alternative .cshtml
To clarify your comments about how to use the alternative, you need to
Copy the file you have at Orchard.Core/Shapes/Views/MenuItem.cshtml over to your theme's view folder so its /Views/MenuItem.cshtml
Rename the copy in your theme to MenuItem-ContentMenuItem.cshtml
Delete probably everything in it and paste in my sample at the start of this post. You don't want most of the original MenuItem.cshtml code in there as it is doing some special tricks to change itself into a different shape which isn't what you want.
Reset your original Orchard.Core/Shapes/Views/MenuItem.cshtml back to the factory default, grab it from the official Orchard repository
Understanding the view names
From your comments you asked about creating more specific views (known as alternates). You can use something call the Shape Tracer to view these. The name of them follows a certain pattern which makes them more and more specific.
You can learn about the alternates on the official docs site:
Accessing and Rendering Shapes
Alternates
To figure out what shape is being used and what alternates are available you can use the shape tracing module which is documented here:
Getting Started with Shape Tracing

View data being cached/failing to refresh

I have a tabbed panel containing different sections of a form. In one section, users are given the ability to add a child document to the currently open document. In a second section, they are given a listbox, where the options are dynamically generated (via #DbLookup) by looking at a view of all the child documents, filtered by the current document's ID. This functionality all works correctly, however, there is a problem with the dynamic listbox options.
When a user adds a new child document, then switches to the next tab, the listbox is not updated with this new document. If they save/re-edit the main document or refresh the page, it makes no different, the user must load another XPage before going back to the original in order for the listbox to update. I have tried to resolve this by doing full updates of the page, using session.evaluate and "NoCache" in the #DBLookup call, or calling database.getView("My view").refresh(), but without luck.
There is also a similar problem where I have a repeat control which uses a view of child documents (again filtered by main document ID) as a datasource. When a user adds a child document using a button, it partially refreshes the repeat - but doesn't show the new child document until the page is refreshed again (or you leave the page and return).
Is there something crucial I am missing with regards to the JSF lifecycle/the way that view data is cached?
As first measure I would add another formula item to the listbox which simply returns the current time (#Now() should work). That way you can check if the listbox options are refreshed on the update in the first place.
If the options are refreshed fine it's indeed clear that the #DbLookup does some caching, although I'm not aware of any default caching logic.
At least for a test I would change the code to use a NotesView object instead of the #DbLookup, something like this:
var nview = database.getView("someview");
var nc = nview.getAllEntriesByKey(currentDocument.getDocument().getUniversalID(), true);
var a = [];
var ve = nc.getFirstEntry();
while (ve) {
a.push(ve.getColumnValues().elementAt(0)); // value of first column
ve = nc.getNextEntry(ve);
}
return a;
(I wrote the code from memory, there may be syntax errors).
Since the code only works with view entries it should be equally fast than the #DbLookup. And you could even do a nview.refresh() if needed.

#SetViewInfo - Issue when clearing filter

I have a problem that have me stumped.
I have been searching for a solution, but haven't found a working one yet. The solutions I seen introduces other issues.
Here is the scenario:
I have a frameset with two frames: 'Navigator' and 'Main'.
In the 'Navigator' frame I display a form called 'Navigator'. It contains an outline, to display a menu.
In the 'Main' frame I display the view selected by the user in the navigator.
So this is a very traditional Notes client application.
I now want to add a checkbox at the top of the view (in the action bar), allowing the user to filter the view by his/her own name. I use #SetViewInfo for this, and it all works perfect.
The issue is when the user switch views. The #SetViewInfo filter stays active when switching to a different view, so after some searching I found some solutions:
In http://www-01.ibm.com/support/docview.wss?uid=swg21204481 IBM suggests to put the following code in the QuerySave event:
#SetViewInfo([SetViewFilter]; temp ; 0 ;1)
When I am switching view or closing the view, I get the error message "Cannot execute the specified command".
In http://www-10.lotus.com/ldd/bpmpblog.nsf/dx/using-setviewinfo-in-a-notes-client-application-to-create-a-user-specific-view Andre Guirard suggests to put the following code in the QuerySave event:
#SetTargetFrame("frameName");
#UpdateFormulaContext;
#Command([OpenView]; #Subset(#ViewTitle; -1));
#SetViewInfo([SetViewFilter]; ""; "columnName"; 1)
I modify this to match my frame name and the programatic name of the first column in my view:
#SetTargetFrame("Main");
#UpdateFormulaContext;
#Command([OpenView]; #Subset(#ViewTitle; -1));
#SetViewInfo([SetViewFilter]; ""; "Adjuster"; 1)
This works perfectly when switching between view. But when I close the application while I am in this particular filtered view, the application is re-opened automatically. This happens no matter if the filter is enabled or not when closing the view.
However, when the view repopens, the frameset is not reloaded, it is just the view with the built-in view navigator to the left.
I finally got this to work by (in the built-in view navigator) selecting another view that the one where I filter data. This fixed the issue for a while, but then it starts again, and the filtered view is active in the navigator.
Obviously it is the OpenView command that is causing this, but if I remove just that line, I get the "Cannot execute the specified command" error again.
Any suggestions/pointers? I am using Notes 8.5.3 running on Windows 7 Professional.
This question can also be found in the IBM developerWorks forum for Notes 8.5:
http://www-10.lotus.com/ldd/nd85forum.nsf/DateAllThreadedWeb/08c73910571306c485257b2b0061ef91
First thing, I would suggest to make sure your view frame is always called "NotesView". You will have much less compatibility issues if you do this.
Secondly, I presume when you say you put it in the QuerySave event you really mean the QueryClose event? Views do not have a QuerySave event.
Thirdly, I find the #UpdateFormulaContext line is not needed. This is what I have in my view QueryClose...
#SetTargetFrame("NotesView");
#Command([OpenView]; #Subset(#ViewTitle; -1));
#SetViewInfo([SetViewFilter]; ""; "<programmaticColumnName>"; 1)
And I can close the app while in the view without any problems.

MonoTouch.Dialog: Dismissing a Keyboard

Using the Reflection API to auto generate a UI.
How can I dismiss the keyboard when the user selects a new field, or if they choose a field which generates a new view to pick from. In the later case, when the user returns to the first screen, the old keyboard is still there.
UIView.EndEditing(bool force);
The above will hide the keyboard for you without needing to know who the first responder is. I haven't done much with the reflection API but you should be able to call that on the view when an element is selected.
Apple Docs -- endEditing:
Clarification for those initially struggling with the MonoDialog portion of the question:
The EndEditing method is not available on DialogViewControllers objects directly (who inherit from UITableViewControllers). You should be calling EndEditing(bool) on the View of a DialogViewController and not trying to call EndEditing(bool) on the actual DialogViewController itself.
For clarification:
DialogViewController dc;
dc.View.EndEditing(true);
Note:
UIView objects include the EndEditing(bool) method, but UITableViewControllers do not inherit from UIView so the EndEditing method is not available on the controller itself. UITableViewControllers contain a view object, call EndEditing on that view object.
Check the ResignFirstResponder method. This one should help you I guess.

Resources