ListView's refresh command not working with binded IRelayCommand - xamarin

I created a form with listview and ISingleOperation fo data refresh.
Then i created command in ViewModel.
public IRelayCommand LoadInvoicesCommand
{
get
{
return GetCommand(() => Execution.ViewModelExecute(new LoadInvoicesOperation(_model), 10000));
}
}
ISingleOperation works well and returns
new Result() { ResultAction = ResultType.None };
Refresh operation is bound well
RefreshCommand="{Binding LoadInvoicesCommand}"
But refresh indicator "hangs" and not disapearing, what is wrong here?

You need to bind a second property from the ListView named IsRefreshing to your ViewModel. This is a boolean property and is the one responsible to tell the ListView that the refreshing has started/completed.
An example of a ListView XAML
<ListView
VerticalOptions="FillAndExpand"
IsPullToRefreshEnabled="true"
RefreshCommand="{Binding LoadInvoicesCommand}"
IsRefreshing="{Binding IsRefreshing, Mode=OneWay}"
ItemsSource="{Binding YourItemSource}"
ItemTemplate="{StaticResource ItemTemplate" />
Your ViewModel will need a public property called IsRefreshing and you will need to set this to false when you the refresh command has completed.

Related

When using a text cell, is it possible to get the value of the text when it is tapped?

The text cell is inside of a listview. I'm populating the text of the text cell with data using Binding. I need to actually get the value of the text when the text cell is clicked on. Is there a way to do this?
XAML file:
<ListView ItemsSource="{Binding MyItems}" ItemTapped="{Binding OnItemTapped}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Key}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListVIew>
You bind the ItemTapped event to a custom event handler using Binding.
In codebehind, e.Item will contain the tapped item, from which you can extract the Key and Value.
Codebehind:
public class MyPage : ContentPage
{
...
private async void OnItemTapped(object sender, ItemTappedEventArgs e)
{
var tappedItem = e.Item;
// do something with tappedItem.Value...
}
}
Edit/Note: You will need to override the ToString() method in your model class in order to display whatever you want. You get the namespace displayed because that's the default behavior of calling ToString() on any object.
You could subscribe to ItemTapped or ItemSelected ListView events and pull your item from ItemTappedEventArgs.Item (in case of ItemTapped event) or SelectedItemChangedEventArgs.SelectedItem (in case of ItemSelected event) . More info in official Xamarin documentation
If you using MVVM approach look at EventToCommandBehavior and Converter.
Xamarin have good example here

Xaml Listview ItemTapped Binding MVVM

I have a Listview in Xaml and I need to bind ItemTapped event to my ModelView using MVVM.
My ListView looks like.
<ListView x:Name="list"
ItemsSource="{Binding employeeList}"
ItemTapped= {Binding selectedItem} >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ItemTapped is an event which, in MVVM, normally corresponds to an ICommand*. If you meant to bind to a normal data property, judging from the attempted binding statement in your XAML snippet, then it would make more sense to do bind ListView's SelectedItem property instead :
<ListView x:Name="list"
ItemsSource="{Binding EmployeeList}"
SelectedItem="{Binding SelectedItem}">
.....
</ListView>
If there is data related action that need to be taken upon ItemTapped event occur, it might instead be implemented on SelectedItem property changed which triggered via binding (as in the XAML binding above) :
private ItemModel _selectedItem;
public ItemModel SelectedItem
{
get { return _selectedItem; }
set
{
if(_selectedItem != value)
{
_selectedItem = value;
OnPropertyChanged();
//this can be placed before or after propertychanged notification raised,
//depending on the situation
DoSomeDataOperation();
}
}
}
*) Xamarin Blog : Turn Events into Commands with Behaviors

how to checkbox checked for all in listbox datasource in wp8?

while selecting all means renaming all the checkbox are checked. my code is below:
<ListBox Name="VillageList">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding isCheched}" Content="{Binding Villages}" IsChecked="False"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
so all checkbox are inside the listbox.how to checked is enable for all checkbox single selection.
public class villageinformation
{
public string Villages{get;set;}
public bool isChecked {get;set;}
}
page.cs{
list<villageinformation> mydataSource=new list<villageinformation>();
myDataSource.Add(new villageinformation(){Village="All",isChecked ="False"});
myDataSource.Add(new villageinformation(){Village="name1",isChecked ="False"});
myDataSource.Add(new villageinformation(){Village="name2",isChecked ="False"});
myDataSource.Add(new villageinformation(){Village="name3",isChecked ="False"});
VillageList.itemSource=myDataSource;
}
so while clicking manually "All" checkbox remaining name1,2,3 are selected how to do this?
If you are using the ObservableCollection for your villages list, which is used for the data binding to the ListBox, then you can set all values in the ObservalbeCollection in the codebehind which shoul update the UI (by checking all the Checkboxes)
you can do it something like this
foreach(var village in VillagesCollection)
{
village.isChecked = true;
}
If you are not able to understand the above, edit your question with how you are setting up the Village data in the code behind file (means .xaml.cs file)

Get selecteditem from listbox using MVVM

I'm using MVVM in this project, I have a listbox which bind to a collection of Customers. I want to create an event to navigate a detailsPage using id of the elementselected:
<ListBox ItemsSource="{Binding Customers}" x:Name="state_list" SelectionChanged="state_list_SelectionChanged">
<i:Interaction.Triggers>
<i:EventTrigger EventName="selectionchanged">
<cmd:EventToCommand Command="{Binding stateSelectedCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding nom}" />
<!--TextBlock Text="{Binding LastName}" />
<TextBlock Text="{Binding Text, ElementName=tbCount}" /-->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I can't figure out how to get the selected item to add it to the uri and then use it to get data. An example or tutorial would be helpful. Thanks :)
I would create a "SelectedCustomer" property in the ViewModel (next to you Customers property) and bind it to the SelectedItem. Then, on the setter of that property you can navigate to your desired page. This way you eliminate the messy events and command.
<ListBox x:Name="state_list
ItemsSource="{Binding Customers}"
SelectedItem="{Binding SelectedCustomer, Mode=TwoWay}">
...
public Customer SelectedCustomer
{
get
{
return _selectedCustomer;
}
set
{
if (value != null)
{
_selectedCustomer = value;
//Navigate to your page here, either with Navigator class or any other mechanism you have in place for changing content on screen
}
}
}
AlexDrenea gives you a good way of binding SelectedItem to a property on your viewmodel. If you are wanting to navigate based on this in an MVVM architecture, I would suggest using messaging to get it done.
I cover this in a blog post I did a while back, but the short summary of doing this within MVVMLight, is to create a Navigator class that sits at the application level.
public class Navigator
{
private PhoneApplicatoinFrame RootFrame;
public Navigator(PhoneApplicationFrame frame)
{
RootFrame = frame;
RegisterMessages();
}
private void RegisterMessages()
{
Messenger.Default.Register<ShowTrackerMessage>(this, ShowTracker);
}
private void ShowTracker(ShowTrackerMessage msg)
{
RootFrame.Navigate(new Uri("/Views/ItemLocationCompassView.xaml", UriKind.RelativeOrAbsolute));
}
}
Then, as part of your application start-up, create it and pass it a reference to your RootFrame:
private static Navigator _navigator;
public static Navigator Nav
{
get { return _navigator; }
}
...
_navigator = new Navigator(this.RootFrame);
Then, you have a couple choices on how you send the Navigation message.
Option 1: In your ViewModel, hook into the PropertyChanged event (part of INotifyPropertyChanged), and send the appropriate message when your SelectedItem property changes.
Option 2: Tie into the SelectionChanged event of your ListBox. I use the MVVMLight's EventToCommand to send that event to a RelayCommand in my ViewModel, then react appropriately to send the message to the Navigator object.
I cover this in more detail at: http://www.smartchitecture.com/?p=27

What is the proper way to perform page navigation on ListBox selection changes

I'm trying the MVVM Light Toolkit. Though I still think having multiple ViewModels for such small apps is overkill, I like the concepts. What I still can't quite understand is how (or I should say "what is the recommended way") to navigate from one page to another when the selection changes in a ListBox.
The big problem with this toolkit is that it forces you to learn MVVM via other sources before using it, rather than show you what (its vision of) MVVM is from within the framework, accompanying samples and documentation. Are there samples out there showing the different concepts? And please, no videos.
Have you tried modifying your ListBox ItemTemplate to have each item be a HyperlinkButton and just setting the NavigateURI attribute to the Page you want to navigate to?
I still have not figured out how to do this (navigate to a details page upon selection changed in a listbox) without any codebehind in the view. However, if you are OK with having just a little codebehind in the view here's what I recommend:
<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}"
SelectionChanged="MainListBox_SelectionChanged"
SelectedItem="{Binding Path=SelectedListItem, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
First, per above bind to the SelectedItem property of the Listbox with a TwoWay binding to a property in your ViewModel (SelectedListItem in the above).
Then in your codebehind for this page implement the handler for MainListBox_SelectionChanged:
// Handle selection changed on ListBox
private void MainListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If selected index is -1 (no selection) do nothing
if (MainListBox.SelectedIndex == -1)
return;
// Navigate to the new page
NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.Relative));
}
This is the only codebehind you need in your main view.
In your main ViewModel you need a SelectedListItem property:
public const string SelectedListItemPropertyName = "SelectedListItem";
private ItemViewModel _SelectedListItem;
/// <summary>
/// Sample ViewModel property; this property is used in the view to display its value using a Binding
/// </summary>
/// <returns></returns>
public ItemViewModel SelectedListItem
{
get
{
return _SelectedListItem;
}
set
{
if (value != _SelectedListItem)
{
_SelectedListItem = value;
RaisePropertyChanged(SelectedListItemPropertyName);
}
}
}
Now, the trick to getting the context passed to your details page (the context being what list item was selected) you need to setup the DataContext in your Details view:
public DetailsPage()
{
InitializeComponent();
if (DataContext == null)
DataContext = App.ViewModel.SelectedListItem;
}
Hope this helps.
eventually you'll want to do more than just navigate, potentially navigate after setting a custom object.
Here is a MVVM-light way of doing this.
You'll first want to bind your listbox selected item to a property in your viewmodel
<ListBox ItemsSource="{Binding Events}" Margin="0,0,-12,0" SelectedItem="{Binding SelectedEvent, Mode=TwoWay}">
Declare your SelectedEvent property
public const string SelectedEventPropertyName = "SelectedEvent";
private Event _selectedEvent;
public Event SelectedEvent
{
get {return _selectedEvent;}
set
{
if (_selectedEvent == value)
{
return;
}
var oldValue = _selectedEvent;
_selectedEvent = value;
// Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
RaisePropertyChanged(SelectedEventPropertyName, oldValue, value, true);
}
}
You can then define an interaction trigger bound to the tap event
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<cmd:EventToCommand Command="{Binding EventPageCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
In your viewmodel, define your EventPageCommand as a RelayCommand:
public RelayCommand EventPageCommand { get; private set; }
public MainViewModel()
{
EventPageCommand = new RelayCommand(GoToEventPage);
}
and finally declare your GoToEventPage method
private void GoToEventPage()
{
_navigationService.NavigateTo(new Uri("/EventPage.xaml", UriKind.Relative));
}
note that you can do other actions before navigating to your new page, plus your selected item from your list box is currently set in the property you bound it too.

Resources