Autocomplete in MVVMCross Xamarin (Android) - mvvmcross

I am trying to create an autocomplete control in Xamarin Android based layout. I am using MVVMCross.
I have created the following AXML layout in my fragment.
<TextView
android:text="Item"
android:layout_column="0"
android:id="#+id/textView42"
android:layout_height="28.6dp"
android:layout_width="86.9dp"
android:gravity="center"
android:layout_marginTop="17.5dp"
android:layout_marginRight="17.5dp" />
<AutoCompleteTextView
android:id="#+id/autocomplete_country"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
local:MvxBind="Adapter Items" />
I had updated my viewmodel to return a string array.
private string[] _items = new string[] { "DD", "DD2" };
public String[] Items
{
get { return this._items; }
set { this._items = value; RaisePropertyChanged<string[]>(() => this._items); }
}
I think I need to use an ArrayAdapter, However I am not sure how to do it. Please provide some guidance/pointers which can help me to proceed.
I am new to Xamarin and MVVMCross, so I might be missing things here.

You don't need a custom Adapter. Switch to MvxAutoCompleteTextView and use MVVMCross binding. Here is an example of how I've used it.
<MvxAutoCompleteTextView
android:id="#+id/DrugName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:hint="Enter drug name..."
android:textSize="#dimen/text_size_xlarge"
local:MvxItemTemplate="#layout/item_drug_notclickable"
local:MvxBind="ItemsSource DrugSuggestions; PartialText DrugSearchTerm; SelectedObject Drug;"
android:layout_gravity="right" />
As Nikola said in the comments you want to be calling RaisePropertyChanged against the Items property not the private variable. That goes for all property changed calls.
One thing to watch out for with the AutoComplete is that changes to the Text must result in a change to the ItemSource. Have a look at this GitHub answer for a full explanation, https://github.com/MvvmCross/MvvmCross/issues/945 of the gotcha

Related

CoordinatorLayout does not hide Toolbar on scrolling despite implementing all required parameters

Here is my setup, i am running a DrawerLayout, within it is a CoordinatorLayout containing an AppBarLayout and a nestedscrollview. I am trying to have the nestedscrollview scroll normally and the Toolbar to get hidden on scrolling down and reppear on scrolling up. Attached within is my XML code. Would appreciate any help.. have read all related questions and implemented their answers without any success.
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout_admin"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.CoordinatorLayout
android:id="#+id/admincoordinator"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include
android:id="#+id/app_bar"
layout="#layout/app_bar"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="#+id/adminrelScroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_drawer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/drawer_header"
app:menu="#menu/menu_drawer" />
I have had the same issue for a week and tried almost everything to solve it.
However I managed to solve the issue.
Where you have something like...
<include
android:id="#+id/app_bar"
layout="#layout/app_bar"
app:layout_scrollFlags="scroll|enterAlways" />
...replace this with whatever is in your app_bar.xml layout. For example:
<android.support.v7.widget.Toolbar
android:id="#+id/main_toolbar"
style="#style/AppTheme.Toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
app:layout_scrollFlags="scroll|enterAlways"/>
It seems that for some reason, scrolling with CoordinatorLayout does not work when using the <include> tag.
I think making use of the new CollapsingToolbarLayout will help…
A short description from some very useful exploration of the new Android Design Support Library shows how to wrap a Toolbar in a CollapsingToolbarLayout and customize effects by setting layout_collapseMode.
update
I think adding an onScrollListener to your ListView and showing/hiding the toolbar like this example from this answer:
getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
listView.setOnScrollListener(new OnScrollListener() {
int mLastFirstVisibleItem = 0;
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) { }
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (view.getId() == listView.getId()) {
final int currentFirstVisibleItem = listView.getFirstVisiblePosition();
if (currentFirstVisibleItem > mLastFirstVisibleItem) {
getSupportActionBar().hide();
} else if (currentFirstVisibleItem < mLastFirstVisibleItem) {
getSupportActionBar().show();
}
mLastFirstVisibleItem = currentFirstVisibleItem;
}
}
});
As #Farbod Salamat-Zadehwas said before: CoordinatorLayout does not work when using the <include> tag.
But you can use <include> this way:
<include
android:id="#+id/app_bar"
layout="#layout/app_bar" />
Parameter app:layout_scrollFlags="scroll|enterAlways" just should be moved into your app_bar.xml if it acceptable for you

Scroll p:messages into view when it is updated and (error) messages are present

I am working with PrimeFaces messages, I want my whole page to scroll to top when p:messages is rendered.
Assign an ID to your p:message component
<p:messages autoUpdate="true" id="myMessage" />
Then, in your backing bean call RequestContext.scrollTo method:
in PrimeFaces >= 6.0:
PrimeFaces.current().scrollTo("myMessage")
in Primefaces < 6.0:
RequestContext context = RequestContext.getCurrentInstance();
context.scrollTo("myMessage");
which is deprecated in PrimeFaces 6.0
Deprecated with PrimeFaces < 6.2
In you backing bean (that one which produces the messages), you should know when you render a p:message. If so simply execute this:
RequestContext.getCurrentInstance().execute("window.scrollTo(0,0);");
Update:
With the newer PrimeFaces versions (>= 6.2), the approach to execute Javascript on the client side is (by using x and y coordinates):
PrimeFaces instance = PrimeFaces.current();
instance.execute("window.scrollTo(0,0);");
To scroll to an element use the element's clientId:
PrimeFaces instance = PrimeFaces.current();
instance.scrollTo("myElementsClientId");
Find more information here:
http://de.selfhtml.org/javascript/objekte/window.htm#scroll_to
examples with jQuery for smooth scrolling as well: Scroll to the top of the page using JavaScript/jQuery?
Lets say that your button is causing the messages to appear.
XHTML
<p:commandButton value="Save"
oncomplete="scrollToFirstMessage()" />
javascript
//javascript function which scroll to the first message in page
function scrollToFirstMessage() {
try {
PrimeFaces.scrollTo($('.ui-message :first-child').eq(0).parent().attr('id'));
} catch(err) {
//No Message was found!
}
}
Hope this helps.
There are valid answers already that show how to scroll to the p:messages component, but they all require you to execute code in a backing bean. This requires you to do / call the same in each action. None show how to scroll to the messages component when it is rendered (updated).
You can implement a phase listener and check messages are present and if the messages component's clientId is present in the PartialViewContext renderIds:
These client identifiers are used to identify components that will be processed during the render phase of the request processing lifecycle.
Your listener can look something like this:
public class MessagesUpdateListener implements PhaseListener {
private final String MESSAGES_ID = "yourMessagesClientId";
#Override
public void afterPhase(PhaseEvent event) {
// Empty
}
#Override
public void beforePhase(PhaseEvent event) {
FacesContext fc = FacesContext.getCurrentInstance();
if (!fc.getMessageList().isEmpty() &&
fc.getPartialViewContext().getRenderIds().contains(MESSAGES_ID)) {
RequestContext.getCurrentInstance().scrollTo(MESSAGES_ID);
}
}
#Override
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE;
}
}
Make sure to register it in your faces-config.xml:
<lifecycle>
<phase-listener>your.MessagesUpdateListener</phase-listener>
</lifecycle>
Tested with XHTML:
<h:form id="main">
<p:messages id="messages" />
<p:inputText id="text1" required="true" />
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
this<br/>is<br/>a<br/>long<br/>page<br/>this<br/>is<br/>a<br/>long<br/>page<br/>
<p:commandButton value="Update" update="messages text1"/>
<p:commandButton value="No update"/>
</h:form>
To check for global messages, use:
fc.getMessageList(null).isEmpty()
See also:
Add global message when field validation fails

How to pass request attribute to HTML:checkbox

Hi
I am creating checkboxes dynamically, so just wanted to know how to pass request attribute to <html:checkbox /> tag.
Eg: request.setAttribute("counter_1", false);
how to set it in below code snippet.
<html:checkbox property=? />
<html:checkbox /> is struts 1.x tag and to get the value from request attribute using jstl you can use below code snippet
<html:checkbox property="${counter_1}" />
You should create ActionForm with your properties like
public class YourForm extends ActionForm {
private boolean counter;
// getters, setters
}
Then declare your form in the struts config. And after that:
<html:checkbox property="counter" />

Registering components with castle that are dynamically created by DynamicProxy

So I've been working hard for a while to build a solution which creates certain components using nothing but Castle DynamicProxy (version 2.2) and an interceptor. Everything looks great except that at the end of all this I realized I need to register these components with the windsor container. Is this possible or has my work been for naught?
I'll fabricate 2 castle configurations to explain my problem. The first one works, while the second does not.
First config (this has been working great for a while):
<castle>
<facilities>
<facility
id="factory.support"
type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel" />
</facilities>
<components>
<component
id="Factory"
service="Foo.IFactory, Foo"
type="Foo.Local.LocalFactory, Foo.Local" />
<component
id="Loader"
service="Foo.Contracts.ILoader, Foo.Contracts"
type="Foo.Local.Loader, Foo.Local"
factoryId="Factory" factoryCreate="GetLoader" />
</components>
</castle>
Second config (I don't know what to put in the type attribute and it doesn't work without it):
<castle>
<facilities>
<facility
id="factory.support"
type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel" />
</facilities>
<components>
<component
id="Factory"
service="Foo.IFactory, Foo"
type="Foo.Remote.RemoteFactory, Foo.Remote" />
<component
id="Loader"
service="Foo.Contracts.ILoader, Foo.Contracts"
type="I DUNNO, WHAT'S THE TYPE?"
factoryId="Factory" factoryCreate="GetLoader" />
</components>
</castle>
So my fabricated configs register the factory facility, then I register a factory, then register my "ILoader" component. The "LocalFactory" creates an actual type for the ILoader component, whereas the "RemoteFactory" creates the ILoader component using dynamic proxy, creating the proxies without targets. I.e., I use the ProxyGenerator.CreateInterfaceProxyWithoutTarget method, so there is no underlying class.
So, is there any hope in registering components as per the second config?
EDIT:
Unfortunately, using the fluent configuration API is not an option at the moment. So to narrow my question down, is it possible to achieve this using the XML configuration?
I believe this is possible via the Fluent Registration API and the "UsingFactoryMethod" mechanism. I have tried to replicate your fabricated scenario in the below test case.
UPDATE
This is in fact possible with XML configuration as well. The trick is just to list the interface itself as the "type" in the configuration (or, equivalently, only specify the "type", as the "service" will be set to the "type" if it is not explicitly provided). I have updated the test case below to include a "TestXml" test that uses xml configuration to achieve your desired result. The "TestFluent" test uses the fluent registration API to achieve it. FYI, I am using Castle Windsor 2.0 here, as I'm guessing that's what you're using.
using Castle.DynamicProxy;
using Castle.Facilities.FactorySupport;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using NUnit.Framework;
namespace CastleTests
{
public interface ILoader
{
void Load();
}
public interface ILoaderFactory
{
ILoader GetLoader();
}
public class LoaderFactory : ILoaderFactory
{
public ILoader GetLoader()
{
return GetLoaderStatic();
}
public static ILoader GetLoaderStatic()
{
return (ILoader) new ProxyGenerator().CreateInterfaceProxyWithoutTarget(typeof (ILoader));
}
}
[TestFixture]
public class DynamicFactoryTests
{
[Test]
public void TestFluent()
{
using (var container = new WindsorContainer())
{
container.AddFacility<FactorySupportFacility>();
container.Register(
Component.For<ILoader>().UsingFactoryMethod(() => LoaderFactory.GetLoaderStatic())
);
var loader = container.Resolve<ILoader>();
Assert.That(loader.GetType().FullName, Is.EqualTo("Castle.Proxies.ILoaderProxy"));
}
}
[Test]
public void TestXml()
{
using (var container = new WindsorContainer("factory.xml"))
{
var loader = container.Resolve<ILoader>();
Assert.That(loader.GetType().FullName, Is.EqualTo("Castle.Proxies.ILoaderProxy"));
}
}
}
}
The content of "factory.xml" is thusly:
<castle>
<facilities>
<facility
id="factory.support"
type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel" />
</facilities>
<components>
<component
id="foo"
service="CastleTests.ILoaderFactory, CastleTests"
type="CastleTests.LoaderFactory, CastleTests" />
<component
id="bar"
type="CastleTests.ILoader, CastleTests"
factoryId="foo" factoryCreate="GetLoader" />
</components>
</castle>

RadioButtonGroup with each RadioButton added in components?

Working in Flex 3, I have a series of components being rendered on a canvas, each of which should represent a single potential selection, ideally in a RadioButtonGroup. So in my parent canvas I am defining the RadioButtonGroup, and each component provides a single RadioButton. However, this doesn't seem to work.
Suppose there is a component called aComponent defined as such:
<mx:Canvas ...>
...
<mx:RadioButton id="someButton" groupName="myRadioButtonGroup" ... />
</mx:Canvas>
The outer canvas:
<mx:Canvas id="outerCanvas" ...>
...
<mx:Script>
public function doesSomething():void
{
var myComponent:aComponent = new aComponent();
outerCanvas.addChild(myComponent);
}
</mx:Script>
...
<mx:RadioButtonGroup id="myRadioButtonGroup" />
</mx:Canvas>
So my guess was that at this point if, say, four of these components were added, the radio buttons would behave in mutually exclusive fashion and I'd be able to access myRadioButtonGroup.selectedValue to get the current selection. However, it doesn't seem to work that way.
Is what I'm trying to do even possible, or have I maybe just missed something?
Thanks!
Edit - got to the bottom of it:
The radiobuttongroup isn't available to the component. It's parent has 'myRadioButtonGroup', but not the component.. Pass the 'myRadioButtonGroup' to the constructor and use it..
outerCanvas function:
var myComponent:aComponent = new aComponent(myRadioButtonGroup);
aComponent definition:
private var radioGroup:RadioButtonGroup;
function aComponent(radioGroup:RadioButtonGroup):void {
this.radioGroup = radioGroup;
}
</mx:Script>
<mx:RadioButton id="someButton" groupName="radioGroup" ... />
untested, but hopefully gives you the idea