Binding in Code Behind with Master/Detail Template - xamarin

I've generated a Master/Detail view app (via Master Detail template of Xamarin, Visual Studio 2019) and I'm trying to perform data binding in Code Behind instead of XAML in the Detail view in order to retrieve and show the "Description" entry:
Therefore I modified my ItemDetailPage.xaml as follows (commented out the section):
<?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="MDDummy.Views.ItemDetailPage"
Title="{Binding Title}">
<!--
<StackLayout Spacing="20" Padding="15">
<Label Text="Text:" FontSize="Medium" />
<Label Text="{Binding Item.Text}" FontSize="Small"/>
<Label Text="Description:" FontSize="Medium" />
<Label Text="{Binding Item.Description}" FontSize="Small"/>
</StackLayout>
-->
</ContentPage>
In the code behind ItemDetailPage.xaml.cs I inserted the following:
namespace MDDummy.Views
{
public partial class ItemDetailPage : ContentPage
{
ItemDetailViewModel viewModel;
public ItemDetailPage(ItemDetailViewModel viewModel)
{
InitializeComponent();
BindingContext = this.viewModel = viewModel;
var layout = new StackLayout
{
Spacing = 40,
Padding = new Thickness(20, 20, 20, 20),
Orientation = StackOrientation.Horizontal
};
var testLabel = new Label();
testLabel.SetBinding(Label.TextProperty, "Description");
testLabel.BindingContext = new {Description = "{Binding Item.Description}"};
layout.Children.Add(testLabel);
Content = layout;
}
}
}
in order to show the "Description" entry via Data Binding. However other than in the xaml file I can't seem to access the related data entry, here "Description" from the Models folder Items.cs
namespace MDDummy2.Models
{
public class Item
{
public string Id { get; set; }
public string Text { get; set; }
public string Description { get; set; }
}
}
and MockDataStore.cs (where the Description entry is located I intend to display in the Detail view).
How can I access the data field, for instance "Description" in code behind in order to show it in the Detail view? Your help is greatly appreciated!

What is the ItemDetailViewModel? You set Label text binding by testLabel.BindingContext = new {Description = "{Binding Item.Description}"};I think it is mistake.
I do one sample about using binding by code behind, you can take a look:
public partial class Page8 : ContentPage
{
private ItemDetailViewModel viewmodel;
public Page8()
{
InitializeComponent();
viewmodel = new ItemDetailViewModel()
{
item = new Item() { Id = "1", Text = "this is item1", Description = "item class description" },
m1 = new model1() {Id="2",Text="this is model1",Description="model1 class description." }
};
var layout = new StackLayout
{
Spacing = 40,
Padding = new Thickness(20, 20, 20, 20),
Orientation = StackOrientation.Horizontal
};
var testLabel = new Label();
testLabel.SetBinding(Label.TextProperty, new Binding("Description",source:viewmodel.item) );
layout.Children.Add(testLabel);
var testLabel1 = new Label();
testLabel1.SetBinding(Label.TextProperty, new Binding("Description",source:viewmodel.m1));
layout.Children.Add(testLabel1);
Content = layout;
this.BindingContext = viewmodel;
}
}
public class Item
{
public string Id { get; set; }
public string Text { get; set; }
public string Description { get; set; }
}
public class model1
{
public string Id { get; set; }
public string Text { get; set; }
public string Description { get; set; }
}
public class ItemDetailViewModel
{
public Item item { get; set; }
public model1 m1 { get; set; }
}

Related

How exactly to use and save images in Xamarin(in ListView)?

i want to be able to take a picture with the emulator, have it create and save an item on the database and display properly on my main Item Page, how do I go about doing this?
i tried my best to only show what is important and related to this and therefore have cut a bunch of stuff out(for example my View for adding items isnt present because i THINK the only part relating to this is the button with a command binding to it leading to the viewmodel)
the reason im asking here is because there are no errors showing, the application doesnt start at all like this and im really confused, i appreciate any and all help and thank you in advance.
if you need any additional info about anything related to this please do ask and i will share it as soon as i see your messeage.
my Item.cs
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string LongDescription { get; set; }
public MediaFile Image { get; set; }
public string Quantity { get; set; }
public string TypeOfQuantity { get; set; }
}
my main page Listview (without the unimportant parts in XAML)
<ListView>
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:Item">
<ViewCell Height="220" xct1:ShadowEffect.Radius="5">
<Grid Padding="7">
<Frame CornerRadius="15">
<StackLayout Orientation="Horizontal">
...// bunch of labels and what not//
</StackLayout>
</StackLayout>
</Frame>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
the Item Creating ViewModel (unrelated things cut out)
public string Name { get; set; }
public string ShDesc { get; set; }
public string LgDesc { get; set; }
public string Qty { get; set; }
public MediaFile Image { get; set; }
public string TypeOfQty { get; set; }
public AsyncCommand AddCommand { get; }
public AsyncCommand PicCommand { get; }
public ItemAddViewModel()
{
AddCommand = new AsyncCommand(Add);
PicCommand = new AsyncCommand(Pic);
}
async Task Add()
{
var name = Name;
var description = ShDesc;
var longdescription = LgDesc;
var qty = Qty;
var typeofqty = TypeOfQty;
var image = Image;
await ItemService.AddItem(name, description, longdescription, qty, typeofqty, image);
Name = ShDesc = LgDesc = Qty = TypeOfQty = null;
}
async Task Pic()
{
var photo = await CrossMedia.Current.TakePhotoAsync(
new StoreCameraMediaOptions
{
SaveToAlbum = true
});
Image = photo;
}
}
}
my Services and DB
public static class ItemService
{
static SQLiteAsyncConnection db;
static async Task Init()
{
//creats Database if it doesnt exist
if (db != null)
return;
var databasePath = Path.Combine(FileSystem.AppDataDirectory, "Mydata.db");
db = new SQLiteAsyncConnection(databasePath);
await db.CreateTableAsync<Item>();
}
//adds item to database
public static async Task AddItem(string Name, string Description,string LongDescription, string Quantity, string TypeOfQuantity, MediaFile image)
{
await Init();
var item = new Item
{
Name = Name,
LongDescription = LongDescription,
Description = Description,
Quantity = Quantity,
TypeOfQuantity = TypeOfQuantity,
Image = image
};
await db.InsertAsync(item);
}

Xamarin Forms Bind Array element inside listView

need to ask you a hand with this one.
I'm currently developing a Xamarin Forms solution using MVVM and i'm in a new situation right now.
I've got a listView with items made by this class
public class City
{
public int Key { get; set; }
public string Value { get; set; }
public List<string> Words{ get; } = new List<string> { "One", "Two", "Three" };
}
What I want to achieve is to display a label text created using the Words list elements indicized by Key. Something like
Words[Key]
Example
<ListView
ItemsSource="{Binding Cities}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand">
<Label Text="{Binding Words[Key]}"
FontSize="18"
TextColor="Black"
VerticalOptions="StartAndExpand" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The label text binding doesn't work, but tecnically is what i need to achieve. For example, if i use Words[0] it will work and returns 'One'
My ViewModel is pretty simple.
public class TestViewModel : INotifyPropertyChanged
{
public ObservableCollection<City> Cities { get; set; }
public TestViewModel()
{
Cities = GetCities();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public ObservableCollection<City> GetCities()
{
return new ObservableCollection<City>
{
new City {Key = 1, Value = "Mumbai"},
new City {Key = 2, Value = "New York"},
new City {Key = 3, Value = "Milan"},
new City {Key = 4, Value = "Rome"}
};
}
}
Do i need to create a property for indexing? In my opinion the problem is that i'm inside a list and already have an index to use.
Thanks for help guys
You can modify your model :
public class City
{
public int Key { get; set; }
public string Value { get; set; }
public List<string> Words { get; } = new List<string> { "One", "Two", "Three" };
public string myValue
{
get
{
return Words[Key];
}
set {}
}
}
And in your .xmal, just set Text="{Binding myValue}" and it will display a list element value of Words.

Xamarin Forms SelectedItem not visible in Picker

I am having some difficulty in getting the selected item binded to a picker. I have been through various answers, but none of it working for me. Here is my code
My XAML
`<Picker x:Name="mobListPicker"
Style="{StaticResource PickerOrangeStyle}" Title="Select Mob" 
HeightRequest="50" ItemsSource="{Binding ProductList, Mode=TwoWay}"
ItemDisplayBinding="{Binding ProductNo}" 
SelectedItem="{Binding SelectedProduct,Mode=TwoWay}"> 
</Picker>`
Property for the selected item
private Product _selectedProduct;
public Product SelectedProduct
{
get { return _selectedProduct; }
set { SetProperty(ref _selectedProduct, value); }
}
It will be awesome if someone can help me identify the error.
I made this simple demo-project about using Picker and MVVM binding. As Item source I use one ObservableCollection of type Person.
When user select one of the items from Picker, value/content of labels bellow is changed. Please take a look at it I think this project is what you need to resolve your issue.
You are not providing us your whole code so it can be hard to see your possible erros. Maybe this can be helpful for you.
Demo:
Code snippets:
My Person class looks like this:
public class Person {
public int PersonId { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public string FullName { get { return $"{FName} {LName}"; } }
public string Biography { get; set; }
}
My ViewModel:
public class AllPersonsViewModel : INotifyPropertyChanged{
public ObservableCollection<Person> AllPersons { get; set; }
private Person selectedPerson;
public Person SelectedPerson {
get { return selectedPerson; }
set { selectedPerson = value;
OnPropertyChanged();
}
}
public AllPersonsViewModel() {
AllPersons = new ObservableCollection<Person>() {
new Person() {
Biography = "Lorem ipsum person 1",
FName = "Person",
LName = "One",
PersonId = 1,
},
new Person() {
Biography = "Lorem ipsum person 2",
FName = "Person",
LName = "Two",
PersonId = 2,
},
new Person() {
Biography = "Lorem ipsum person 3",
FName = "Person",
LName = "Three",
PersonId = 3,
},
};
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName]string propertyName = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
I have one view which use this view-model as BindingContext
... and XAML of my page with Picker control is here:
<?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="XF.Picker.Demo.Views.PersonsPage">
<ContentPage.Content>
<StackLayout Orientation="Vertical">
<Picker Title="All person"
ItemDisplayBinding="{Binding FullName}"
ItemsSource="{Binding AllPersons}"
SelectedItem="{Binding SelectedPerson}"/>
<!-- Margin just to see picker dropdown and labels at the same time-->
<Label Text="{Binding SelectedPerson.FullName}" Margin="0,80,0,0"/>
<Label Text="{Binding SelectedPerson.Biography}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
I published this code project on github you can find it here

Picker item source binding from view model

I am trying to bind the values for a picker from a model in view model, there I am getting path of the model instead of the values.
<Picker x:Name="LocationPicker"
Title="Location" HeightRequest="40"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
SelectedItem="{Binding Location}"
ItemsSource="{Binding MaintainRoomTypes}"/>
Here is my view model code:
if (jobDetailsForFitter != null)
{
WindowDetails = new WindowDetailsModel
{
Windows = jobDetailsForFitter.Windows,
Locations = jobDetailsForFitter.Locations,
RoomTypes = jobDetailsForFitter.RoomTypes,
AddFiles = jobDetailsForFitter.AddFiles
};
Locations = jobDetailsForFitter.Locations;
MaintainRoomTypes = jobDetailsForFitter.RoomTypes;
await FitterService.Instance.LoadJobDetailsToLocalStore(jobDetailsForFitter, SelectedJob?.Id ?? 0);
}
how to bind itemsource to get list.
public List<Room> Locations { get; set; }
public List<RoomTypeModel> RoomTypes { get; set; }
You have to define ItemDisplayBinding property to Picker.
For eg:
public class Room
{
public string RoomNumber { private set; get; }
public string RoomName { private set; get; }
}
And you want to display RoomName in Picker
<Picker ItemsSource="{Binding Room}" ItemDisplayBinding="{Binding RoomName}"/>
Hope this will solve your problem.

Binding does not work, what am I doing wrong?

Binding in the collection Items works perfectly, but when I try to Binding the variable Count does not work, could anyone help me with this?
<Label Text="{Binding Count}" TextColor="#4F4F4F" FontSize="10" FontAttributes="Bold"/>
I did a test, moving the Label out of the ListView and it worked perfect, but I need it to work from within the Listview.
ViewModel:
class ListViewModel : INotifyPropertyChanged
{
public ObservableCollection<Item> Items { get; }
public ListViewModel()
{
Items = new ObservableCollection<Item>(new[]
{
new Item { Text = "Test 1", Detail = "Detail 1", Foto = "computer2.png" },
new Item { Text = "Test 2", Detail = "Detail 2", Foto = "computer4.png" },
});
private int count = 1;
public int Count
{
get { return count; }
set
{
count = value;
OnPropertyChanged();
}
}
XAML:
<ListView
ItemsSource="{Binding Items}"
<ListView.Header>
<StackLayout>
<Label Text="{Binding Count}"
TextColor="#4F4F4F" FontSize="10"
FontAttributes="Bold"/>
</StackLayout>
</ListView.Header>
</ListView>
try something like the following. Also i'm assuming what you've posted isn't your full code, as we can't see your implementation of OnPropertyChanged or how you are setting the count.
<ContentPage
//BlahBlah Headings
x:Name="PageName">
<ListView ItemsSource="{Binding Items}">
<ListView.Header>
<StackLayout>
<Label Text="{Binding Source={x:Reference PageName}, Path=BindingContext.Count}"
TextColor="#4F4F4F" FontSize="10"
FontAttributes="Bold"/>
</StackLayout>
</ListView.Header>
</ListView>
</ContentPage>
I have done this little repo and it works without particular bindings
ViewModel + Model
namespace TestRelativeLayout.ViewModels
{
[ImplementPropertyChanged]
public class MyPage4ViewModel
{
public ObservableCollection<Item> Items { get; set; }
public int Counter { get; set; } = 111;
public string MyCounterFooter { get; set; } = "888";
public MyPage4ViewModel() {
Items = new ObservableCollection<Item>(new[]
{
new Item { Text = "Test 1", Detail = "Detail 1", Foto = "computer2.png" },
new Item { Text = "Test 2", Detail = "Detail 2", Foto = "computer4.png" },
});
}
public class Item
{
public string Detail { get; set; }
public string Foto { get; set; }
public string Text { get; set; }
}
}
}
Xaml
namespace TestRelativeLayout.ViewModels
{
[ImplementPropertyChanged]
public class MyPage4ViewModel
{
public ObservableCollection<Item> Items { get; set; }
public int Counter { get; set; } = 111;
public string MyCounterFooter { get; set; } = "888";
public MyPage4ViewModel() {
Items = new ObservableCollection<Item>(new[]
{
new Item { Text = "Test 1", Detail = "Detail 1", Foto = "computer2.png" },
new Item { Text = "Test 2", Detail = "Detail 2", Foto = "computer4.png" },
});
}
public class Item
{
public string Detail { get; set; }
public string Foto { get; set; }
public string Text { get; set; }
}
}
}

Resources