Xamarin.Forms How to active a button once the form is filled - xamarin.forms

<Frame HasShadow="False">
<StackLayout Orientation="Vertical" >
<Entry Placeholder="NAME" x:Name="name"></Entry>
<Entry Placeholder="SURNAME" x:Name="surname"></Entry>
<StackLayout Orientation="Horizontal" >
<Label Text="BIRTHDATE" VerticalOptions="Center" HorizontalOptions="Center" ></Label>
<DatePicker x:Name="birdthdate" HorizontalOptions="Center" VerticalOptions="Center"></DatePicker>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="PICK YEARS" HorizontalOptions="Center" VerticalOptions="Center"></Label>
<Picker Title="YEARS" x:Name="years" HorizontalOptions="Center" VerticalOptions="Center"></Picker>
</StackLayout>
<StackLayout Spacing="0">
<Label Text="Number of docs:"></Label>
<Entry Keyboard="Numeric" x:name="docs"></Entry>
</StackLayout>
<Button Text="SAVE" TextColor="White" Padding="0,-20" BackgroundColor="#07987f" IsEnabled="false" >
</Button>
</StackLayout>
</Frame>
My idea is only when user will enter Name Surname Birdthdate Years NumberOfDocs the button will become enable and can save the data. Any suggestion how to do that?

Here is the logic for a simple login with login name + password, where the login button only gets enabled when LoginName and LoginPassword contains text:
private string _loginName;
public string LoginName
{
get { return _loginName; }
set
{
SetProperty(ref _loginName, value);
RaisePropertyChanged("IsLoginButtonEnabled");
}
}
private string _loginPassword;
public string LoginPassword
{
get { return _loginPassword; }
set
{
SetProperty(ref _loginPassword, value);
RaisePropertyChanged("IsLoginButtonEnabled");
}
}
public bool IsLoginButtonEnabled
{
get
{
if (!string.IsNullOrEmpty(LoginName) &&
!string.IsNullOrEmpty(LoginPassword))
{
return true;
}
return false;
}
}
Just extend this to your needs and it should work.

There are multiple ways you can do that. The easiest way is like the answer from Dennis Schröer. But it doesn't look like you are using MVVM so i have another solution using converters.
Change your button to this:
<Button Padding="0,-20"
BackgroundColor="#07987f"
Text="SAVE"
TextColor="White">
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource EnableButtonConverter}">
<Binding Path="Text"
Source="{x:Reference name}" />
<Binding Path="Text"
Source="{x:Reference surname}" />
<Binding Path="Date"
Source="{x:Reference birdthdate}" />
<Binding Path="SelectedItem"
Source="{x:Reference years}" />
</MultiBinding>
</Button.IsEnabled>
</Button>
The property IsEnabled is bound to all the properties you want it to be dependent on.
The converter does the logic:
public class EnableButtonConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var name = (string)values[0];
var surname = (string)values[1];
//var date = (DateTime)values[2];
//var year = (string)values[3];
return !string.IsNullOrWhiteSpace(name) && !string.IsNullOrWhiteSpace(surname); //&& !year.Equals("YEARS"); //Todo: add a check for the date
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Put the Converter in your pages ResourceDictionary and you are good to go.
PS: It's better for performance to use Grid-layout instead of multiple StackLayouts

Related

Command RelativeSource not working in Xamarin

I have Binding Data problem in subpages. I have a Page that shows a list of products. When clicking on the product it will go to the Product Details subpage. Everything works fine:
Product.xaml
<RefreshView x:DataType="locals:DashboardViewModel" Padding="0" Command="{Binding LoadDashboardCommand}" IsRefreshing="{Binding IsBusy, Mode=OneWay}">
<StackLayout BindableLayout.ItemsSource="{Binding ProductNew}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Frame x:DataType="model:Product">
<StackLayout>
<Label FontSize="14" MaxLines="2" LineBreakMode="TailTruncation" HeightRequest="40" Text="{Binding Name}"/>
</StackLayout>
<Frame.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1"
Command="{Binding Source={RelativeSource AncestorType={x:Type locals:DashboardViewModel}}, Path=ProductTappedView}"
CommandParameter="{Binding .}" />
</Frame.GestureRecognizers>
</Frame>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</RefreshView>
Product.xaml.cs
DashboardViewModel dashboardViewModel;
public Product()
{
BindingContext = dashboardViewModel = new DashboardViewModel(Navigation);
dashboardViewModel.OnAppearing();
}
DashboardViewModel.cs
public class DashboardViewModel : BaseDashboardViewModel
{
public Command LoadDashboardCommand { get; }
public Command ProductTappedView { get; }
public ObservableCollection<Product> ProductNew { get; }
public DashboardViewModel(INavigation _navigation)
{
LoadDashboardCommand = new Command(async () => await ExecuteLoadDashboardCommand());
ProductNew = new ObservableCollection<Product>();
ProductTappedView = new Command<Product>(OnViewDetailProduct);
Navigation = _navigation;
}
private async void OnViewDetailProduct(Product detailProduct)
{
await Navigation.PushAsync(new ProductDetail(detailProduct));
}
............
}
Next in my Productdetail page show product details. I have Read more. When clicked it will redirect to another subpage: ContentDetailProd.xaml
ProductDetail.xaml
<ContentPage.BindingContext>
<locals:ViewDetailProductViewModel/>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout Padding="15">
<Label Text="{Binding ProductNews.Name}" FontFamily="RobotoMedium" FontSize="18" TextTransform="Uppercase"/>
<Label Text="Read more"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Command="{Binding Source={RelativeSource AncestorType={x:Type locals:ViewDetailProductViewModel}}, Path=ContentProductTappedView}" CommandParameter="{Binding .}" />
</StackLayout.GestureRecognizers>
</StackLayout>
</ContentPage.Content>
ViewDetailProductViewModel.cs
public class ViewDetailProductViewModel : BaseDashboardViewModel
{
public Command ContentProductTappedView { get;}
public ViewDetailProductViewModel()
{
ProductNews = new Product();
ContentProductTappedView = new Command<Product>(OnViewContentDetailProduct);
}
private async void OnViewContentDetailProduct(Product detailProduct)
{
await Navigation.PushAsync(new ContentDetailProd(detailProduct));
}
}
ContentDetailProd.xaml.cs
public ContentDetailProd(Product detailProduct)
{
InitializeComponent();
//Load Readmore
}
However when I Debug it actually doesn't run on the event: ContentProductTappedView and as a result it doesn't redirect to the ContentDetailProd.xaml page. I've tried everything but still can't solve the problem.
Looking forward to everyone's help. Thanks
If you want to pass the data through a Page Constructor, you could refer to the link below. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/hierarchical#passing-data-when-navigating
I changed like this based on the documentation #Wendy Zang - MSFT provided. Everything looks good.
ProductDetail.xaml
<StackLayout x:Name="_readmore" Padding="15">
<Label Text="{Binding ProductNews.Name}" FontFamily="RobotoMedium" FontSize="18" TextTransform="Uppercase"/>
<Label x:Name="_content" MaxLines="2" LineBreakMode="TailTruncation" Text="{Binding ProductNews.Contents}" FontFamily="RobotoMedium" FontSize="18" TextTransform="Uppercase"/>
<Label Text="Read more"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="_readmore_Tapped" />
</StackLayout.GestureRecognizers>
</StackLayout>
ProductDetail.xaml.cs
private async void _readmore_Tapped(object sender, EventArgs e)
{
var contentget = _content.Text;
var detailProduct = new Product
{
Contents = contentget,
};
var detailContentPage = new ContentDetailProd(detailProduct);
detailContentPage.BindingContext = detailProduct;
await Navigation.PushAsync(detailContentPage);
}
ContentDetailProd.xaml.cs
public ContentDetailProd(Product detailProduct)
{
InitializeComponent();
//Load Readmore
if (detailProduct != null)
{
_contentmore.Text = detailProduct.Contents;
}
}

how to bind isenabled property to entry in MVVM when I click on submit button in xamarin forms

I am facing an issue when I submit my form in xamarin form using mvvm architecture my form UI is still able and user can interact while fetching the data from server. I want to disable my UI elements when my submit button is running to fetch the data from server. Actually, I want to bind isEnabled property in my viewmodel. But I do not know how to set it to bool value from my view model and then bind it to the UI elements. What i need to add in my set function so that when someone click on submit button my UI elements will be inactive and user can not edit till the response comes from server.
what to do please assist. Here is my code.
Blockquote
<StackLayout>
<Entry x:Name="entryFullName"
Text="{Binding FullName}"
Placeholder="Full Name"
IsEnabled="{Binding block}"
/>
<Picker x:Name="pickerGender"
Title="Gender"
ItemsSource="{Binding Genders}"
SelectedItem="{Binding SelectedGender}"
IsEnabled="{Binding gender}"
/>
</StackLayout>
<StackLayout>
<Button x:Name="btnSubmit"
Command="{Binding SubmitCommand}"
Text="Submit"
/>
</StackLayout>
<ActivityIndicator IsVisible="{Binding IsBusy}" IsRunning="{Binding IsBusy}" />
here is my code for my viewmodel submit button function
Blockquote
private string _Block;
public string Block
{
get { return _Block }
set { _Block = value; OnPropertyChanged(); }
}
private void OnSubmit()
{
if (string.IsNullOrEmpty(this.FullName))
{
this.ErrorOccurred?.Invoke(this, "Please enter full name");
return;
}
Device.BeginInvokeOnMainThread(async () => await this.SaveProfile();
}
first, bind all of your IsEnabled properties to the same VM property
<Entry x:Name="entryFullName" IsEnabled="{Binding NotBusy}" ... />
<Picker x:Name="pickerGender" IsEnabled="{Binding NotBusy}" ... />
...
<Button x:Name="btnSubmit" IsEnabled="{Binding NotBusy}" ... />
then in your MV create a bool property
private bool _NotBusy = true;
public bool NotBusy
{
get { return _NotBusy }
set { _NotBusy = value; OnPropertyChanged(); }
}
finally, when saving set the property
private void OnSubmit()
{
if (string.IsNullOrEmpty(this.FullName))
{
this.ErrorOccurred?.Invoke(this, "Please enter full name");
return;
}
NotBusy = false;
Device.BeginInvokeOnMainThread(async () => await this.SaveProfile();
}
you can add a property IsNotSubmitting,
private bool _isNotSubmitting = true;
public bool IsNotSubmitting {
get => _isNotSubmitting ;
set {
_isNotSubmitting = value;
OnPropertyChanged();
}
}
binding in Xaml:
<Entry x:Name="entryFullName"
Text="{Binding FullName}"
Placeholder="Full Name"
IsEnabled="{Binding IsNotSubmitting}" />
now you can set "IsNotSubmitting=false" in the beginning of method SubmitCommand, and you can set "IsNotSubmitting=true" when the commiting is finished

How to implement a listView "quick filtering" like week calendar view?

I've created a customer specific task management app with tasks placed on specific dates (and sometime hours), but here the date is important.
I'm using a listView and have a DatePicker setting for selected other dates than today. So far so good.
I would like to implement a week quick-filter option so that e.g., the dates of the current week is displayed at the top of the list view and a click on a certain date would filter the listView accordingly. Kind of a standard outlook-like week view.
How would I do this in the best way?
CustomControl that I put above the listView?
ViewPager control?
Any ideas or suggestions much appreciated.
P.S. I need to be able to target both Android and iOS.
Set two Properties in the ViewModel one for containing all the Items EntireCollection and another to store the Filtered Items FilteredCollection. On button click derive the Filtered item from entire list using Where.
ViewModel
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<ListItem> filteredCollection;
public ObservableCollection<ListItem> FilteredCollection
{
get
{
return filteredCollection;
}
set
{
filteredCollection = value;
OnPropertyChanged();
}
}
private ObservableCollection<ListItem> entireCollection;
public ObservableCollection<ListItem> EntireCollection
{
get
{
return entireCollection;
}
set
{
entireCollection = value;
OnPropertyChanged();
}
}
public ViewModel()
{ ...
this.FilterCollection = this.EntireCollection;
...
}
}
Button clicked
void Button_Clicked(System.Object sender, System.EventArgs e)
{
DateTime selectedDate = ((DateTime)((sender as VisualElement).BindingContext)).Date;
viewModel.FilteredCollection = new ObservableCollection<ListItem>(viewModel.EntireCollection.Where(x =>
{
if (DateTime.Equals(x.DateAdded, selectedDate))
{
var asd = x.DateAdded.Day;
return true;
}
return false;
}));
}
XAML
<StackLayout>
<ScrollView
x:Name="calender"
Orientation="Horizontal">
<StackLayout
BackgroundColor="Blue"
BindableLayout.ItemsSource="{Binding Dates}"
Orientation="Horizontal">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Button
TextColor="White"
BackgroundColor="Blue"
Clicked="Button_Clicked"
Text="{Binding Day}"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
<ListView
ItemsSource="{Binding FilteredCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}"/>
<Label Text="{Binding DateAdded}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Hope it helps!!

Custom content view with Label-Entry duplicates Xamarin forms

I have custom content view with a Label as title and another Label as detail and an edit Icon ; when the icon is clicked detail label is converted to Entry to make changes and the changes are carried over to binding.
I have bound multiple of these custom views to different properties of same object and trying to edit each one and move to next one, the problem is it seems to duplicate the individual views
I have also put x:Name but still it duplicates same value to the views above it ..
Just the edit of Lastname
Now if I move to 3rd view and edit it , it replicates new value to all previously edited values. - for lastname in this case which is weird considering its not same view used in the page and on debug it hits the method only once.
Custom content view:
<StackLayout Orientation="Horizontal"
VerticalOptions="Start"
Padding="25,10,25,10">
<StackLayout x:Name="stackLayoutDetail"
HorizontalOptions="FillAndExpand">
<Label x:Name="title"
Text="{Binding Title}" />
<Label x:Name="detail"
Text="{Binding Detail}"
FontSize="Large"
FontAttributes="Bold" />
</StackLayout>
<Image x:Name="editIcon"
Source="edit_icon.png"
WidthRequest="25"
HeightRequest="25"
IsVisible="{Binding EditIconVisible}">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="EditIcon_Clicked" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
Code behind:
private static Entry newEntry = new Entry();
public static readonly BindableProperty DetailProperty = BindableProperty.Create(propertyName: nameof(Detail),
returnType: typeof(string),
declaringType: typeof(LabelledEntrywithIcon),
defaultValue: default(string));
public string Detail
{
get
{
return (string)GetValue(DetailProperty);
}
set => SetValue(DetailProperty, value);
}
private void EditIcon_Clicked(object sender, System.EventArgs e)
{
detailLabel = (Label)stackLayoutDetail.Children[1];
stackLayoutDetail.Children.RemoveAt(1);
newEntry.Text = Detail;
stackLayoutDetail.Children.Add(newEntry);
editIcon.IsVisible = false;
newEntry.Completed += NewEntry_Completed;
}
private void NewEntry_Completed(object sender, System.EventArgs e)
{
try
{
var _newText = newEntry.Text;
detailLabel.Text = _newText;
stackLayoutDetail.Children.RemoveAt(1);
stackLayoutDetail.Children.Add(detailLabel);
Detail = _newText;
editIcon.IsVisible = true;
}
catch (System.Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
Page
<local:LabelledEntrywithIcon x:Name="firstName"
Title="First Name"
Detail="{Binding Fella.FirstName}" />
<local:LabelledEntrywithIcon x:Name="lastname"
Title="Last Name"
Detail="{Binding Fella.LastName}" />
<local:LabelledEntrywithIcon x:Name="gender"
Title="Gender"
Detail="{Binding Fella.Gender}" />
Code behind:
ViewModel=new MainViewModel();
BindingContext = ViewModel;
Complete code to test is at Github repo : https://github.com/pmahend1/CustomViewDuplicationIssue
Strange but I changed a line of code and it works as expected now.
On the class variables changed private static Entry newEntry= new Entry(); to
private static Entry newEntry;
in EditIcon_Clicked method instead of newEntry.Text = Detail; used
newEntry = new Entry { Text = Detail };
I am not sure why it was taking same reference even though its new Entry for each LabelledEntrywithIcon
Instead of creating a new entry and finding and removing the label and adding the new entry after, you could simplify your problem by:
<StackLayout Orientation="Horizontal"
VerticalOptions="Start"
Padding="25,10,25,10">
<StackLayout x:Name="stackLayoutDetail"
HorizontalOptions="FillAndExpand">
<Label x:Name="title"
Text="{Binding Title}" />
<Label x:Name="detail"
Text="{Binding Detail}"
IsVisible="{Binding ShowLabel}"
FontSize="Large"
FontAttributes="Bold" />
<Entry ... IsVisible="{Binding ShowEntry}" ... />
</StackLayout>
<Image x:Name="editIcon"
Source="edit_icon.png"
WidthRequest="25"
HeightRequest="25"
IsVisible="{Binding ShowLabel}">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="EditIcon_Clicked" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
Note that I intentionally wrote ... inside the entry element as Placeholder for all customizations you might want do there (font size, etc...).
Now you add two BindablyProperties (type bool) ShowEntry and ShowLabel, where ShowLabel defaults to true and ShowEntry defaults to false.
Now all you have to do is to adapt your EditIcon_Clicked Event:
private void EditIcon_Clicked(object sender, System.EventArgs e)
{
ShowLabel = false;
ShowEntry = true;
newEntry.Text = Detail;
newEntry.Completed += NewEntry_Completed;
}
And adapt NewEntry_Completed to
private void NewEntry_Completed(object sender, System.EventArgs e)
{
try
{
var _newText = newEntry.Text;
detailLabel.Text = _newText;
ShowLabel = true;
ShowEntry = false;
Detail = _newText;
}
catch (System.Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
Basically this does the same as your solution, however you save yourself from having to push UI Items around in your codebehind and especially the bugs and errors coming with it.

Using SQlite to bind GroupedItems Template but only getting GroupNames

This code is from the datasource class. I am fetching the list of customers from the SQLite database and storing it in ObservableCollection. Using GetGroups() I am creating the groups based on some property:
public ObservableCollection<CustomerDetails> GetAllCustomers()
{
using (var con = new SQLiteConnection(app.DBPath))
{
ObservableCollection<CustomerDetails> newCol = new ObservableCollection<CustomerDetails>(con.Query<CustomerDetails>("Select * from CustomerDetails"));
return newCol;
}
}
public IEnumerable<IGrouping<int,CustomerDetails>> GetGroups()
{
return GetAllCustomers().OrderBy(x=>x.CustomerName).GroupBy(x=>x.CustomerPropertyType);
}
This is how I am binding the Grid View
CustomerImplementation objCustomerImp = new CustomerImplementation();
var all = objCustomerImp.GetGroups();
this.DefaultViewModel["Groups"] = all;
XAML File:
CustomerName, ContactNo1 and EmailId are properties inside DataSource. All are bound in the code above.
<CollectionViewSource
x:Name="groupedItemsViewSource"
Source="{Binding Groups}"
IsSourceGrouped="true"/>
<GridView
x:Name="itemGridView"
IsItemClickEnabled="True"
IsSwipeEnabled="True"
Grid.RowSpan="2"
Padding="116,136,116,46"
ItemsSource="{Binding Mode=OneWay, Source={StaticResource groupedItemsViewSource}}"
SelectionMode="Single"
SelectedItem="0">
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Width="320" Height="240">
<StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding CustomerName}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="48" Margin="15,0,15,0"/>
<TextBlock Text="{Binding ContactNo1}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="48" Margin="15,0,15,0"/>
<TextBlock Text="{Binding EmailId}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="48" Margin="15,0,15,0"/>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="1,0,0,6">
<Button
AutomationProperties.Name="Group Title"
Style="{StaticResource TextPrimaryButtonStyle}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Key}" Margin="3,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" />
<TextBlock Text="{StaticResource ChevronGlyph}" FontFamily="Segoe UI Symbol" Margin="0,-7,0,10" Style="{StaticResource GroupHeaderTextStyle}"/>
</StackPanel>
</Button>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
I believe SQLite-net is implemented lazily, so the query doesn't actually give any results until you try to access the items in the collection. Try putting ToList() at the end of the Query call:
public ObservableCollection<CustomerDetails> GetAllCustomers()
{
using (var con = new SQLiteConnection(app.DBPath))
{
// add ToList() to query to instantiate the results
ObservableCollection<CustomerDetails> newCol = new ObservableCollection<CustomerDetails>(con.Query<CustomerDetails>("Select * from CustomerDetails").ToList());
return newCol;
}
}
I recreated your solution and found the problem in DefaultViewModel. Use your own implementation of DefaultViewModel, or call it MainViewModel, which implements INotifyPropertyChanged, e.g.:
public class MainViewModel : INotifyPropertyChanged
{
private IEnumerable<IGrouping<int, CustomerDetails>> groups = null;
public IEnumerable<IGrouping<int, CustomerDetails>> Groups
{
get { return groups; }
private set { Set(ref groups, value); }
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private bool Set<T>(ref T storage, object value, [CallerMemberName] string propertyName = null)
{
if (object.Equals(storage, value))
return false;
storage = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
return true;
}
#endregion
}
Then set the DataContext of your Page to an instance of MainViewModel, and set the Groups property with data you want (should be in MainViewModel too, e.g., with some LoadGroups method). CollectionViewSource in page resources references to Groups property of your MainViewModel and you will see your data in the GridView.

Resources