How can I keep an item, in an MvxListView
, highlighted until it is unselected or until another item is selected?
My program has an MvxListView
that correctly displays a list of items. The user can select an item, by clicking it, and then click a save button. The selected item is stored in MyChosenItem
until it is needed by the save button code. Currently, the selected item stays highlights for a split second before returning to the unselected color.
This is how the MvxListView
is created:
<Mvx.MvxListView
android:layout_width="match_parent"
android:layout_height="260dp"
android:layout_marginTop="40dp"
android:id="@+id/MyMvxListViewControl"
local:MvxBind="ItemsSource MyItems; SelectedItem MyChosenItem"
local:MvxItemTemplate="@layout/my_item_layout" />
This is Layout/my_item_layout.xaml
:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res/Project.Ui.Droid"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="300.0dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="20dp"
android:textColor="#000000"
local:MvxBind="Text Field1" />
<TextView
android:layout_width="250.0dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="20dp"
android:textColor="#000000"
local:MvxBind="Text Field2" />
</LinearLayout>
This method provides an easy way to customize which items remain highlighted. I settled on this because it gives me full control over what is highlighted and how it is displayed in the list. (This example shows highlighting only one item, but it could easily be extended to highlight more.)
The MvxListView, in the original question, links to MyItems
and MyChosenItem
in the associated view model. MyItems
is a collection of Item
, and MyChosenItem
is just a single Item
. I added isItemSelected
to Item
. The Item
class looks like this now:
public class Item : MvxViewModel
{
private string _field1;
private string _field2;
private bool _isItemSelected = false;
public string Field1
{
get { return _field1; }
set
{
_field1= value;
RaisePropertyChanged("Field1");
}
}
public string Field2
{
get { return _field2; }
set
{
_field2= value;
RaisePropertyChanged("Field2");
}
}
public bool isItemSelected
{
get { return _isItemSelected; }
set
{
_isItemSelected = value;
RaisePropertyChanged("isItemSelected");
}
}
}
Note: The Item
class extends MvxViewModel
so that RaisePropertyChange()
can be called. This allows my_item_layout.xaml
to be notified when that property changes.
Update each instance of isItemSelected
from the property that the MvxListView's SelectedItem
binds to. In this case, that's the MyChosenItem
property in the associated view model. This is what the new code looks like:
public Item MyChosenItem
{
get { return _myChosenItem; }
set
{
if (_myChosenItem != value)
{
_myChosenItem = value;
UpdateItemSelections();
RaisePropertyChanged("MyChosenItem");
}
}
}
// Select MyChosenItem and unselect all other items
private void UpdateItemSelections()
{
if( MyItems.Count > 0)
{
for (int index = 0; index < MyItems.Count; index++)
{
// If the chosen item is the same, mark it as selected
if (MyItems[index].Field1.Equals(MyChosenItem.Field1)
&& MyItems[index].Field2.Equals(MyChosenItem.Field2))
{
MyItems[index].isItemSelected = true;
}
else
{
// Only trigger the property changed event if it needs to change
if (MyItems[index].isItemSelected)
{
MyItems[index].isItemSelected = false;
}
}
}
}
}
It would be pretty easy to modify UpdateItemSelections()
to any selection behavior you want.
Make each row do something based on the isItemSelected
property. I just made the background change colors by controlling the visibility property of a view. However, all sorts of things are possible. isItemSelected
could even be passed to a custom control for some really interesting visuals. My new Layout/my_item_layout.xaml
looks like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res/Project.Ui.Droid"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!-- SELECTED BACKGROUND COLOR -->
<View
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FF0000"
local:MvxBind="Visibility isItemSelected,Converter=BoolToViewStates" />
<TextView
android:layout_width="300.0dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="20dp"
android:textColor="#000000"
local:MvxBind="Text Field1" />
<TextView
android:layout_width="250.0dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="20dp"
android:textColor="#000000"
local:MvxBind="Text Field2" />
</LinearLayout>
EDIT
It might be better to use an MvxCommand
instead of triggering the highlighted action when the SelectedItem
is set. It seems the SelectedItem
is only set if it is not already selected. Tapping an item will select it. Tapping another item will change the selection. Tapping the same item again will not unselect it. This means that once an item is selected, one item must remain selected. If you need the ability to unselect all the items in the list, follow these modifications to the original instructions:
Add an MvxCommand
to the view model. Call UpdateItemSelections()
from the MvxCommand
instead of from MyChosenItem
.
public MvxCommand ItemSelectedCommand { get; private set; }
// Constructor
public ItemSelectionViewModel()
{
ItemSelectedCommand = new MvxCommand(OnItemSelected);
}
public Item MyChosenItem
{
get { return _myChosenItem; }
set
{
if (_myChosenItem != value)
{
_myChosenItem = value;
//UpdateItemSelections(); // Move this to OnItemSelected()
RaisePropertyChanged("MyChosenItem");
}
}
}
private void OnItemSelected()
{
UpdateItemSelections();
}
Change UpdateItemSelections()
to toggle the isItemSelected
property instead of always setting it to true:
// Select MyChosenItem and unselect all other items
private void UpdateItemSelections()
{
if( MyItems.Count > 0)
{
for (int index = 0; index < MyItems.Count; index++)
{
// If the chosen item is the same, mark it as selected
if (MyItems[index].Field1.Equals(MyChosenItem.Field1)
&& MyItems[index].Field2.Equals(MyChosenItem.Field2))
{
// Toggle selected status
MyItems[index].isItemSelected = !MyItems[index].isItemSelected;
}
else
{
// Only trigger the property changed event if it needs to change
if (MyItems[index].isItemSelected)
{
MyItems[index].isItemSelected = false;
}
}
}
}
}
Remember to check MyChosenItem.isItemSelected == true
when saving or doing anything that acts on the selected item in the list. There might be a value in MyChosenItem
that is unselected in the list view the user sees.
Bind the MvxCommand
to ItemClick
in layout definition of the MvxListView
:
<Mvx.MvxListView
android:layout_width="match_parent"
android:layout_height="260dp"
android:layout_marginTop="40dp"
android:id="@+id/MyMvxListViewControl"
local:MvxBind="ItemsSource MyItems; SelectedItem MyChosenItem; ItemClick ItemSelectedCommand"
local:MvxItemTemplate="@layout/my_item_layout" />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With