c# Prism connection between two ViewModels - c#

I'm developing a Xamarin Forms application, which uses Prism for MVVM, and I have some problems, more precisely in establishing a connection between two ViewModels.
In my MainPage I have a UserControl and a Label(TextBlock), the UserControl have a picker(ComboBox).
What I want to achieve is to establish a connection between the MainPageViewModels and UserControlViewModel, so that each time the user changes the selection in the picker, the UserControlViewModel informs MainPageViewModels then, it can change the value of the Label(TextBlock).
There is my code:
MainPage:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:MyNewApp.Views"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="MyNewApp.Views.MainPage">
<ContentPage.Content>
<StackLayout>
<views:UserControl x:Name="UserControl"/>
<Label Text="{Binding NumberChosen}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
MainPageViewModel:
using Prism.Events;
using Prism.Mvvm;
namespace MyNewApp.ViewModels
{
class MainPageViewModel : BindableBase
{
private int _NumberChosen;
public int NumberChosen
{
get { return _NumberChosen; }
set { SetProperty(ref _NumberChosen, value); }
}
public MainPageViewModel()
{
// Must Read the value on the picker of the UserControl.
NumberChosen = 0;
}
}
}
UserControl:
<?xml version="1.0" encoding="utf-8" ?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="MyNewApp.Views.UserControl">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Text="Pick a number:"/>
<Picker Grid.Row="1"
ItemsSource="{Binding NumericSource}"
SelectedItem="{Binding NumberSelected}"
/>
</Grid>
UserControlViewModel
using Prism.Events;
using Prism.Mvvm;
using System.Collections.ObjectModel;
namespace MyNewApp.ViewModels
{
public class UserControlViewModel : BindableBase
{
public ObservableCollection<int> NumericSource { get; set; }
private int _NumberSelected;
public int NumberSelected
{
get { return _NumberSelected; }
set { SetProperty(ref _NumberSelected, value); }
}
public UserControlViewModel()
{
var source = SourceCreator();
NumericSource = source;
NumberSelected = source[0];
}
ObservableCollection<int> SourceCreator()
{
ObservableCollection<int> sourceCreator = new ObservableCollection<int>();
for (int i = 21; i < 99; i++)
{
sourceCreator.Add(i);
}
return sourceCreator;
}
}
}
Appreciate your help.

1- Define bindable property in UserControl called NumberChosen
2- in UserControl's Xaml, bind NumberChosen to NumberSelected (SelectedItem of your picker) ( You can bind it SelectedItem of your picker directly too)
https://www.c-sharpcorner.com/article/binding-control-to-control-in-xamarin-forms/
3- In main page, if you want to show that in your view only, you can bind control to control as mentioned before.
4- You can also bind ChosenNumber of user control to a property in your main view model too

Related

MAUI: ListView Binding With Custom ViewCell

I use FreshMvvm to develop and run MAUI project on Windows.
But I have some binding issues with ListView and my custom template.
The following is my code:
Model:
public class BaseModel
{
public string Code{ get; set; }
}
public class NameModel: BaseModel
{
public string Name{ get; set; }
}
ViewModel:
public class MainPageModel : FreshBasePageModel
{
private readonly IApiService _apiService;
private List<NameModel> _nameModelList;
public List<NameModel> NameModelList
{
get => _nameModelList;
private set
{
_nameModelList= value;
RaisePropertyChanged(nameof(NameModelList));
}
}
public MainPageModel(IApiService apiService)
{
_apiService = apiService;
}
protected override void ViewIsAppearing(object sender, EventArgs e)
{
base.ViewIsAppearing(sender, e);
Task.Run(() => GetNameData());
}
private async Task GetNameData()
{
var result = await _apiService.GetNameData();
NameModelList= result.GetRange(1, 10);
}
}
I create a list and use an api service to get a name model list data.
If api service gets the data, NameModelList will be updated.
NameModelList is the property which will be bind on Listview.ItemsSource
MainPage.xmal:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyNamespace.ViewCells.CustomListViewCell"
x:Class="MyNamespace.Pages.MainPage"
BackgroundColor="{DynamicResource SecondaryColor}">
<Grid RowSpacing="25"
RowDefinitions="Auto"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<ListView
x:Name="MyListView"
ItemsSource="{Binding NameModelList}"
Grid.Row="0"
WidthRequest="800"
HeightRequest="800"
BackgroundColor="Gray"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<local:MyCustomViewCell/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</ContentPage>
Custom ViewCell (.xml):
<ViewCell xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyNamespace.ViewCells.CustomListViewCell.MyCustomViewCell">
<Grid RowSpacing="100" WidthRequest="100" HeightRequest="100">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*" />
</Grid.ColumnDefinitions>
<StackLayout
GridLayout.Row="0"
GridLayout.Column="0">
<Label
Text="{Binding Code}"
FontSize="30"/>
<Label
Text="{Binding Name}"
FontSize="30"/>
</StackLayout>
</Grid>
</ViewCell>
Custom ViewCell (.cs)
public partial class MyCustomViewCell: ViewCell
{
public static readonly BindableProperty CodeProperty =
BindableProperty.Create("Code", typeof(string), typeof(MyCustomViewCell), "");
public string Code
{
get { return (string)GetValue(CodeProperty); }
set { SetValue(CodeProperty, value); }
}
public static readonly BindableProperty NameProperty =
BindableProperty.Create("Name", typeof(string), typeof(MyCustomViewCell), "");
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
}
I define a custom ViewCell files and put this ViewCell in the Listview of MainPage.
Now my question is my Listview can't show data successfully.
I'm sure that NameModelList has value and its count is more than 1.
But I can see nothing.
The output log has no error, and the breakpoints in MyCustomViewCell.cs are never triggered.
So I think I have some binding issues, but I can't find it out.
To get to the bottom of this I took your code and put it in a project so I could have a little play with it. You can find the repo here. Not to be rude here or anything, but might be a good idea for a next question to do that yourself, that will help speed things up :)
Anyway, the problem is much more subtle. Because you're using XAML for your layout, you'll have to call InitializeComponent in the constructor. So adding this to your MyCustomViewCell made it work:
public MyCustomViewCell()
{
InitializeComponent();
}

How to send an argument to ContentView?

I'm trying to create a ContentPage that contains a TabView from XamarinCommunityToolkit.
Lets say that the Tabs define an ObservableCollection of Categories, and every TabViewItem should load a ContentView and passes a GroupId as an Argument / Property, and then I use that GroupId to filter Products list.
What's the best way to passe an argument to the ContentView ?
Update :
I've tried to use BindablePropertiy but, in the debugger, I can see the newValue recieved, but nothing shows in the Label :
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
mc:Ignorable="d"
x:Class="mynamespace.Views.MainPage"
Title="{Binding Title}"
xmlns:local="clr-namespace:mynamespace.Views"
xmlns:vm="clr-namespace:mynamespace.ViewModels"
xmlns:model="clr-namespace:mynamespace.Models"
x:Name="MainPage">
<ContentPage.Content>
<xct:TabView Grid.Row="0"
TabStripPlacement="Top"
TabStripBackgroundColor="White"
TabStripHeight="48"
TabIndicatorColor="Orange"
TabIndicatorHeight="2"
TabItemsSource="{Binding Categories}">
<xct:TabView.TabViewItemDataTemplate>
<DataTemplate>
<Grid>
<Label Text="{Binding Name}"
FontAttributes="Bold"
VerticalOptions="Center"
Padding="6, 0"/>
</Grid>
</DataTemplate>
</xct:TabView.TabViewItemDataTemplate>
<xct:TabView.TabContentDataTemplate>
<DataTemplate>
<local:GroupView GroupId="{Binding Id}" />
</DataTemplate>
</xct:TabView.TabContentDataTemplate>
</xct:TabView>
</ContentPage.Content>
GroupView.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace mynamespace.Views
{
public partial class GroupView : ContentView
{
public string GroupId
{
get { return (string)GetValue(GroupIdProperty); }
set { SetValue(GroupIdProperty, value); }
}
public static readonly BindableProperty GroupIdProperty = BindableProperty.Create(
nameof(GroupId),
typeof(string),
typeof(GroupView),
"Default_V",
defaultBindingMode: BindingMode.OneWay,
propertyChanged: GroupIdChanged
);
private static void GroupIdChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (ProductListPage)bindable;
control.GroupId = newValue?.ToString();
}
public GroupView()
{
InitializeComponent();
BindingContext = this;
}
}
}
GroupView.xaml
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="mynamespace.Views.GroupView">
<ContentView.Content>
<StackLayout>
<Label Text="{Binding GroupId}" /> <!-- Shows nothing -->
</StackLayout>
</ContentView.Content>
</ContentView>
Category class :
public class Category
{
private string id;
private string name;
private string description;
public string Id { get => id; set => id = value; }
public string Name { get => name; set => name = value; }
public string Description { get => description; set => description = value; }
}
ProductListViewModel.cs
public class ProductListViewModel : BaseViewModel
{
public string GroupId { get; set; }
public ProductListViewModel()
{
}
public ProductListViewModel(string groupId)
{
GroupId = groupId;
}
}
Update :
[0:] Binding: 'GroupId' property not found on 'mynamespace.Models.Category', target property: 'Xamarin.Forms.Label.Text'
Don't assign bindings internally inside custom controls. You could do like this:
public partial class GroupView : ContentView
{
GroupViewModel _viewModel;
public string GroupId
{
get { return (string)GetValue(GroupIdProperty); }
set { SetValue(GroupIdProperty, value); }
}
public static readonly BindableProperty GroupIdProperty = BindableProperty.Create(
nameof(GroupId),
typeof(string),
typeof(GroupView),
"Default_V",
defaultBindingMode: BindingMode.OneWay,
propertyChanged: GroupIdChanged
);
private static void GroupIdChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (GroupView)bindable;
control.GroupId = (string)newValue;
control.label.Text = control.GroupId;
}
public GroupView()
{
InitializeComponent();
}
}
then in xaml:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="mynamespace.Views.GroupView">
<ContentView.Content>
<StackLayout>
<Label x:Name="label" />
</StackLayout>
</ContentView.Content>
</ContentView>

Can not pass binding context through Navigation.pushasync with collectionview in xamarin

I am new to Xamarin and am making a small prototype application. Since this is a pilot project, I am keeping it simple and not using MVVM.
Expected output: I have a collection view and when I select an item from that view, I would like to bind the data from that Item, and navigate to a new page. I want the new page to be binded with the data I selected from the collection view as there will be a couple buttons on that page with different options.
Problem: When the item is selected from the collection view, I use Navigation.pushasync to open a new page. Inside of that routing action, I set the binding context to the data from the selected item. When I navigate to the page, none of the page is populated with data from the binding context I set in the previous page.
Comment: I had this working with a list view. But I wanted more flexibility in my styles for my list, so I am trying a collection view. I am having trouble trying to understand the way to bind data with a collection list vs a listview.
Main Page View:
MainPage.xaml:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.MainPage"
Title="My Numbers">
<ContentPage.ToolbarItems>
<ToolbarItem Text="+"
Clicked="OnNumberAddedClicked" />
<ToolbarItem Text="Q"
Clicked="GetCount"/>
<ToolbarItem Text="L"
Clicked="GetLast"/>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<CollectionView x:Name="listView"
SelectionMode="Single"
ItemsSource="{Binding listView}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackLayout Orientation="Vertical"
Grid.Column="1">
<Label Text="{Binding MyNumber}" FontSize="Title"/>
<Label Text="{Binding DateAdded}" FontSize="Subtitle"/>
</StackLayout>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</ContentPage.Content>
</ContentPage>
MainPage.xaml.cs:
using System;
using Xamarin.Forms;
using Notes.Models;
namespace Notes
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
listView.SelectionChanged += ListView_SelectionChanged;
}
async void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var num = e.CurrentSelection;
if (num != null)
{
await Navigation.PushAsync(new ActionsPage
{
BindingContext = num as NUM
});
}
}
protected override async void OnAppearing()
{
base.OnAppearing();
listView.ItemsSource = await App.Database.GetNumbersAsync();
}
}
}
Action Page View:
The circle is where the label is supposed to be, but the data won't bind.
ActionsPage.xaml:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Notes.ActionsPage"
Title="NUM Actions">
<StackLayout>
<Label Text="{Binding myNumber}"
FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
<Button Text="Delete NUM"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
Clicked="OnDeleteButtonClicked" />
</StackLayout>
</ContentPage>
ActionsPage.xaml.cs:
using Notes.Models;
using System;
using Xamarin.Forms;
namespace Notes
{
public partial class ActionsPage : ContentPage
{
public ActionsPage()
{
InitializeComponent();
}
async void OnDeleteButtonClicked(object sender, EventArgs e)
{
var num = (NUM)BindingContext;
await App.Database.DeleteNumAsync(num);
await Navigation.PopAsync();
}
}
}
Any help is appreciated
The simple way to pass value on navigation is just to pass an argument in the constructor.
MainPage SelectionChanged event:
private async void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var num = e.CurrentSelection[0] as NUM;
if (num != null)
{
await Navigation.PushAsync(new ActionsPage(num));
}
}
ActionPage:
public partial class ActionsPage : ContentPage
{
public int myNumber { get; set; }
public ActionsPage(NUM num)
{
InitializeComponent();
myNumber = num.MyNumber;
this.BindingContext = this;
}
async void OnDeleteButtonClicked(System.Object sender, System.EventArgs e)
{
//var num = (NUM)BindingContext;
//await App.Database.DeleteNumAsync(num);
//await Navigation.PopAsync();
}
}

I'm looking for a more reliable option in Xamarin

I dont know how is it called.
I need to create something that works this way:
Do button, when you click button under button you have list and you can choos one option. List should be button's width.
You can find it in aplication to choose for example language of country.
Do Xamarin built-in something to create this? Or can someone show me how implement this?
Or you could roll your own in Forms, something like:
ImagePickerDropDown.xaml:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ImagePickerDropdownSample.ImagePickerDropdown"
x:Name="imagePickerDropDown" >
<ContentView.Content>
<StackLayout>
<ImageButton x:Name="mainButton"
Source="{Binding Source={x:Reference imagePickerDropDown}, Path=SelectedImage}"
Clicked="ImageClicked" />
<StackLayout x:Name="stackView"
BindableLayout.ItemsSource="{Binding Source={x:Reference imagePickerDropDown}, Path=Images}"
IsVisible="False">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<ImageButton Source="{Binding .}" Clicked="ImageSelected"/>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
</ContentView.Content>
</ContentView>
ImagePickerDropDown.xaml.cs:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Xamarin.Forms;
namespace ImagePickerDropdownSample
{
public partial class ImagePickerDropdown : ContentView
{
public ImagePickerDropdown()
{
InitializeComponent();
}
private void ImageSelected(object sender, EventArgs e)
{
var imageSource = (sender as ImageButton).Source;
SelectedImage = imageSource;
mainButton.IsEnabled = true;
stackView.IsVisible = false;
}
private void ImageClicked(object sender, EventArgs e)
{
mainButton.IsEnabled = false;
stackView.IsVisible = true;
}
public static readonly BindableProperty SelectedImageProperty =
BindableProperty.Create(nameof(SelectedImage), typeof(ImageSource), typeof(ImagePickerDropdown), null);
public ImageSource SelectedImage
{
get
{
return (ImageSource)GetValue(SelectedImageProperty);
}
set
{
SetValue(SelectedImageProperty, value);
}
}
public static readonly BindableProperty ImagesProperty =
BindableProperty.Create(nameof(Images), typeof(ObservableCollection<ImageSource>), typeof(ImagePickerDropdown), null);
public ObservableCollection<ImageSource> Images
{
get
{
return (ObservableCollection<ImageSource>)GetValue(ImagesProperty);
}
set
{
SetValue(ImagesProperty, value);
}
}
}
}
Using it XAML:
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="ImagePickerDropdownSample.MainPage"
xmlns:local="clr-namespace:ImagePickerDropdownSample"
Padding="0,50,0,0"
BackgroundColor="Black">
<StackLayout
x:Name="mainLayout">
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="Start"
TextColor="White"/>
<local:ImagePickerDropdown SelectedImage="{Binding SelectedImage}"
Images="{Binding Images}"
WidthRequest="50"
HorizontalOptions="Center"
BackgroundColor="Black"/>
</StackLayout>
</ContentPage>
Using it code behind:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace ImagePickerDropdownSample
{
// Learn more about making custom code visible in the Xamarin.Forms previewer
// by visiting https://aka.ms/xamarinforms-previewer
[DesignTimeVisible(false)]
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
Images = new ObservableCollection<ImageSource>();
Images.Add(new FileImageSource() { File = "image1.png" });
Images.Add(new FileImageSource() { File = "image2.png" });
Images.Add(new FileImageSource() { File = "image3.png" });
SelectedImage = Images[0];
BindingContext = this;
}
ImageSource _selectedImage;
public ImageSource SelectedImage
{
get
{
return _selectedImage;
}
set
{
if (_selectedImage != value)
{
_selectedImage = value;
OnPropertyChanged(nameof(SelectedImage));
}
}
}
ObservableCollection<ImageSource> _images;
public ObservableCollection<ImageSource> Images
{
get
{
return _images;
}
set
{
if (_images != value)
{
_images = value;
OnPropertyChanged(nameof(Images));
}
}
}
}
}
Use a Spinner .. basically you need to first create an ArrayAdapter then attach the ArrayAdapter to a Spinner :
//we need a List of some type because the ArrayAdapter takes one as param
var items = new List<string>() {"one", "two", "three"};
//instantiate the ArrayAdapter with context, your Resource is a layout, items is the List
var adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleSpinnerItem, items);
//then instantiate your spinner
var spinner = FindViewById<Spinner>(Resource.Id.spinner);
//and attach the adapter to the spinner like this
spinner.Adapter = adapter;
from #Aaron He
Create android spinner dynamically in Xamarin

How can I add an icon to the NavigationBar in all pages?

So I'm trying to implement an icon in my NavigationBar, so it can be visible in all my pages... I'm using xamarin forms so I want it to be able in both android and IOS... I'm not sure how to do this, but I was trying to add this in my MyCar.xaml
<customControls:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
xmlns:views="clr-namespace:OficinaDigitalX.Views"
xmlns:customControls="clr-namespace:OficinaDigitalX.ViewModel"
x:Name="MyCar">
<customControls:BasePage.Content>
<AbsoluteLayout>
<StackLayout Padding="10, 0, 10, 0">
<ListView
ItemsSource="{Binding Path=CarList}"
IsPullToRefreshEnabled="False"
SelectedItem="{Binding Path=SelectedCar}">
<ListView.Header>
<Label Text="Os Meus Carros" FontSize="Large" />
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding VID}"
TextColor="Black"
Detail="{Binding LicensePlate}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</AbsoluteLayout>
</customControls:BasePage.Content>
</customControls:BasePage>
This is my MyCar.xaml.cs
namespace OficinaDigitalX.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyCar : ViewModel.BasePage
{
public MyCar()
{
Extensions.LoadFromXaml(this, typeof(MyCar));
BindingContext = new MyCarViewModel(Navigation);
}
this is my MyCarViewModel.cs
public class MyCarViewModel : ViewModelBase
{
public MyCarViewModel()
{
}
public MyCarViewModel(INavigation navigation)
{
this.Navigation = navigation;
this.SelectedCar = null;
GetClientCars();
}
private List<CarInfo> _CarList;
public List<CarInfo> CarList
{
get
{
return _CarList;
}
set
{
_CarList = value;
OnPropertyChanged("CarList");
}
}
private CarInfo _SelectedCar;
public CarInfo SelectedCar
{
get
{
return _SelectedCar;
}
set
{
_SelectedCar = value;
OnPropertyChanged("SelectedCar");
if (_SelectedCar != null)
ChangeWindow(_SelectedCar);
}
}
public INavigation Navigation { get; set; }
private void ChangeWindow(CarInfo car)
{
Navigation.PushAsync(new Interactions(car));
this.SelectedCar = null;
}
public void GetClientCars()
{
string command = "asdasd";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(MainPage.server + command));
request.ContentType = "application/json";
request.Method = "POST";
//request.ContentLength = 999999;
using (var stream = new StreamWriter(request.GetRequestStream()))
{
string postData = JsonConvert.SerializeObject(command);
//stream.Write(postData);
stream.Flush();
stream.Close();
}
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
using (var responseString = new StreamReader(response.GetResponseStream()))
{
CarList = JsonConvert.DeserializeObject<List<CarInfo>>(responseString.ReadToEnd());
}
}
catch (WebException ex)
{
using (StreamReader reader = new StreamReader(ex.Response.GetResponseStream()))
{
}
throw;
}
}
}
}
Can anyone help with this?
The correct way of doing this in my Knowledge is extending the content page:
public class BasePage : ContentPage
{
public ICommand CartItemCommand { get; set; }
public ICommand NotificationPageCommand { get; set; }
public BasePage() : base()
{
CartItemCommand = new Command(async () => await GoCartItemCommand());
NotificationPageCommand = new Command(GoNotificationPage);
Init();
}
private void Init()
{
this.ToolbarItems.Add(new ToolbarItem()
{
Icon = "nav_notification_btn",
Command = NotificationPageCommand,
});
this.ToolbarItems.Add(new ToolbarItem()
{
Icon = "nav_cart_btn",
Command = CartItemCommand
});
}
}
}
And once you are done with that just use this BasePage everywhere in Place of ContentPage
In your XAML
<customControls:Basepage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
xmlns:views="clr-namespace:OficinaDigitalX.Views"
x:Class="OficinaDigitalX.MainPage"
xmlns:customControls="Your Control NameSpace"
x:Name="Main"
NavigationPage.HasNavigationBar="True">
</customControls:Basepage>
And in your Xaml.cs file
public partial class MainPage: BasePage
See to it that both partial classes inherit from one base class i.e BasePage or ContentPage as per your need.
And when you do not want to use the NavBar controls just inherit your XAML classes
from a Normal ContentPage.
Goodluck revert in case of queries!
You have two ways to implement this:
1- NavigationPage.TitleView which you can put your icon in that with the Image tag.
2- Using a custom control named NavBarView and use that in your pages inside ControlTemplate attribute.
The implementation of NavBarView could be like this :
<?xml version="1.0" encoding="UTF-8" ?>
<ControlTemplate
x:Class="YourAppName.View.Controls.NavBarView"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="46" />
<RowDefinition Height="1" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackLayout
Padding="10,5"
x:DataType="vm:XeposBaseViewModel"
BackgroundColor="{StaticResource XeposHeaderBackgroundColor}"
BindingContext="{TemplateBinding BindingContext}"
Orientation="Horizontal">
<!-- YOUR NAVBAR CONTENT HERE -->
</StackLayout>
<BoxView Grid.Row="1" BackgroundColor="Black" />
<ContentPresenter Grid.Row="2" />
</Grid>
</ControlTemplate>
And usage should be like this:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="YourAppName.View.Sell.SomeView"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:YourAppName.View.Controls;assembly=YourAppName.View"
ControlTemplate="{StaticResource NavBar}">
<!-- Your other page data is here -->
</ContentPage>
NavBar is defined in App.xaml like this, so you can use it with StaticResource:
<controls:NavBarView x:Key="NavBar" />

Categories

Resources