XAML template binding in Windows 8 - data-binding

I am walking through Windows Store Sample Application XAML Twitter Client 1, to get the same features in my own application. But i can't get binding work in 1 to 1 sample page.
This is my grid for displaying friends:
<GridView x:Name="FriendsGrid"
Grid.Row="2"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10,10,0,0"
ItemsSource="{Binding Friends}"
ItemTemplate="{StaticResource FriendItemTemplate}"
Grid.ColumnSpan="2">
<GridView.DataContext>
<Model:FriendsViewModel/>
</GridView.DataContext>
Template for binding:
<Page.Resources>
<DataTemplate x:Key="FriendItemTemplate">
<Grid Height="200" Width="300">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image HorizontalAlignment="Left"
Height="80" Width="130"
Margin="10,10,0,0"
VerticalAlignment="Top"
Source="{Binding RealPhoto}"
Stretch="UniformToFill"/>
<TextBlock Grid.Column="1"
HorizontalAlignment="Left"
Margin="10,10,0,0"
TextWrapping="Wrap"
VerticalAlignment="Top"
Height="80"
Width="130"
Text="{Binding FirstName}"/>
<TextBlock HorizontalAlignment="Left"
Margin="10,10,0,0"
Grid.Row="1"
TextWrapping="Wrap"
Text="{Binding LastName}"
VerticalAlignment="Top"
Width="280" Height="80"
Grid.ColumnSpan="2" />
</Grid>
</DataTemplate>
</Page.Resources>
In my code-behind file:
private FriendsViewModel _model;
public MyPage()
{
this.InitializeComponent();
_model = new FriendsViewModel();
FriendsGrid.DataContext = _model;
}
Than i populate model, in application i see exactly the same items count that i`ve added, but items are empty. Using debug i see, that model is not empty.
Also when i am hard-coding values in templates, they are visible.
Test project on GitHub

I forgot to add getters and setters to properties of my model. Initially i had this:
public double Uid;
Than i added {get; set;}
[DataContract]
public class Friend
{
[DataMember(Name = "uid")]
public double Uid { get; set; }
[DataMember(Name="first_name")]
public string FirstName { get; set; }
[DataMember(Name="last_name")]
public string LastName { get; set; }
[DataMember(Name="online")]
public bool Online { get; set; }
[DataMember(Name = "photo")]
public string Photo { get; set; }
public ImageSource RealPhoto { get; set; }
}

To see changes in your view model you need to implement INotifyPropertyChanged. Part of doing this is calling NotifyPropertyChanged on a property if its value changes.

Related

Change toObservableCollection does not update UI

I am new to Xamarin Forms. So therefore I have a trouble with the UI updating. I had create a collection view to display a list of data. Besides that I also created a button for the user to update remarks. While the user click the button, it will call OnRemarksButtonClickedAsync(APIPatrolD obj) and update the patrold_remark to the ObservationList. I already debug and ensure that the remarks had been store in the DAPIPatrolDSiapImbasList but it unable to update to the UI. Did anyone known why?
Below is my source code.
APIDATA Class
public class APIPatrolH
{
public string patrolh_ID { get; set; }
public DateTime patrolh_planDateTime { get; set; }
public DateTime patrolh_actualDateTime { get; set; }
public string patrolh_actualBy { get; set; }
public string patrolh_route { get; set; }
public string patrolh_routeDesc { get; set; }
public APIPatrolD[] patrolh_patrold { get; set; }
}
public class APIPatrolD
{
public string patrold_ID { get; set; }
public string patrold_loc { get; set; }
public int patrold_seq { get; set; }
public string patrold_desc { get; set; }
public byte[] patrold_image { get; set; }
public string patrold_GPS { get; set; } //latitude,longtitue. If 0,0 then no gps tracking
public string patrold_takenGPS { get; set; } //filled by apps
public DateTime patrold_takenDateTime { get; set; } //filled by apps - scan date time
public string patrold_remark { get; set; } //filled by apps
}
Base View Model
public class BaseViewModel : INotifyPropertyChanged
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
View Model
public string _patrold_remark;
public string patrold_remark
{
get { return _patrold_remark; }
set
{
_patrold_remark = value;
OnPropertyChanged();
}
}
public ObservableCollection<APIPatrolD> _DAPIPatrolDSiapImbasList;
public ObservableCollection<APIPatrolD> DAPIPatrolDSiapImbasList
{
get { return _DAPIPatrolDSiapImbasList; }
set
{
if (_DAPIPatrolDSiapImbasList != value)
{
_DAPIPatrolDSiapImbasList = value;
OnPropertyChanged();
}
}
}
public SecurityPortalDetailsPageViewModel(DAPIPatrolH dAPIPatrolH, int v)
{
DAPIPatrolDSiapImbasList = new ObservableCollection<APIPatrolD>();
}
private async void OnRemarksButtonClickedAsync(APIPatrolD obj)
{
// To Do display a customize PopUps=
var result = await App.Current.MainPage.Navigation.ShowPopupAsync(new CustomizePopups(obj));
foreach (APIPatrolD aPIPatrolD in DAPIPatrolDSiapImbasList) {
if (aPIPatrolD.patrold_loc == obj.patrold_loc) {
aPIPatrolD.patrold_remark = (string)result;
break;
}
}
OnPropertyChanged("DAPIPatrolDSiapImbasList");
}
UI Page
<CollectionView Grid.Row="2"
Grid.ColumnSpan="2"
ItemsSource="{Binding DAPIPatrolDSiapImbasList,Mode=TwoWay}">
<CollectionView.EmptyView>
<StackLayout>
<Label Text="Tiada Rekod" HorizontalOptions="CenterAndExpand" TextColor="Black" FontAttributes="Bold" FontSize="18" VerticalOptions="CenterAndExpand"/>
</StackLayout>
</CollectionView.EmptyView>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="1.2*"/>
<ColumnDefinition />
<ColumnDefinition Width="0.1"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="55"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="3" />
</Grid.RowDefinitions>
<Label FontSize="15" FontAttributes="Bold" Text="{Binding patrold_seq}" TextColor="#403f3f" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
<Label FontSize="15" FontAttributes="Bold" Grid.Column="1" Text="{Binding patrold_loc}" TextColor="#403f3f" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand"/>
<Label FontSize="15" FontAttributes="Bold" Grid.Column="2" Text="{Binding patrold_desc}" TextColor="#403f3f" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand"/>
<Label FontSize="15" FontAttributes="Bold" Grid.ColumnSpan="5" Grid.Row="1" Text="{Binding patrold_takenDateTime, StringFormat='{dd/MM/yy hh:mm tt}'}" TextColor="#403f3f" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand"/>
<Label FontSize="15" FontAttributes="Bold" Grid.ColumnSpan="5" Grid.Row="2" x:Name="Remarks" Text="{Binding patrold_remark}" TextColor="#403f3f" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand"/>
<Button Text="Pemerhatian" FontSize="9" FontAttributes="Bold" Grid.Column="3" BackgroundColor="Red" HeightRequest="30" WidthRequest="120" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
Command="{Binding Path=BindingContext.RemarksCommand, Source={x:Reference _SecurityPortalDetailsPage}}"
CommandParameter="{Binding .}"
TextTransform="None"
/>
<controls:CFrame Grid.Row="3" Grid.ColumnSpan="5" BackgroundColor="LightGray"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Refer to the following code:
`
public class APIPatrolD:INotifyPropertyChanged
private string _patrold_loc;
public string patrold_loc {
get { return _patrold_loc; }
set {
_patrold_loc = value;
OnPropertyChanged("patrold_loc");
}
}
`

How to bind without RelativeSource FindAncestor?

I need some binding help on my Uno UWP Project.
I have the following objects:
public class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<Picture> Pictures {get;set;}
public int ImageWidth {get;set;}
}
public class Picture : INotifyPropertyChanged
{
public string URL {get;set;}
public int ImageWidth {get;set;}
}
I have the following view:
<Page>
<Grid>
<Grid.RowDefinition>
<RowDefinition Height=*/>
<RowDefinition Height="Auto"/>
</Grid.Rowdefinition>
<GridView ItemsSource="{Binding Pictures}" SelectionMode="Extended" IsMultiSelectCheckBoxEnabled="False"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch" SelectionChanged="ImageSelectionChanged" >
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="Margin" Value="10"/>
</Style>
</GridView.ItemContainerStyle>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid MaximumRowsOrColumns="5" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate>
<Grid Margin="4">
<Image Source="{Binding URL}" Width="{Binding ImageWidth,Mode=TwoWay}" MinWidth="200"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
<Slider Grid.Row="1" Width="200" Minimum="200" Maximum="1500" StepFrequency="100" TickPlacement="Outside" VerticalAlignment="Bottom" Margin="20,0"
Value="{Binding ImageWidth, Mode=TwoWay}" />
</Grid>
</Page>
The Page DataContext is ViewModel. This works, because the Picture class has an ImageWidth. Instead, I would like to bind to the ViewModel.ImageWidth property.
How can I do this in Uno?
Assuming you want your Slider to change the width of all pictures,
you can share the ImageWidth by changing your entities like this:
public class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<Picture> Pictures {get;set;}
public int ImageWidth {get;set;}
}
public class Picture : INotifyPropertyChanged
{
public ViewModel Parent {get;}
public string URL {get;set;}
}
and then use the following binding in the item template:
<Image Source="{Binding URL}"
Width="{Binding Parent.ImageWidth}"
MinWidth="200"/>

How to dynamically set element visibility of items in a list view in xamarin forms

I am trying to create a page in Xamarin forms which mimics a table style in HTML. I want the header and data to be able to remove or displayed based on the condition. My problem is I could not figure out a way to access certain property inside the ViewCell of List view.
My XAML code is like this
<Grid x:DataType="models:TransactionHistory" >
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Grid.Row="0"
Grid.Column="0"
Text="Tran Number"
x:Name="LabelTranNumber"
IsVisible="{Binding ShowTransactionNumberColumn}"/>
<Label Grid.Row="0"
Grid.Column="1"
Text="Description"
x:Name="LabelDescription"
IsVisible="{Binding ShowDescriptionColumn}"/>
<Label
Grid.Row="0"
Grid.Column="2"
Text="Quantity"
x:Name="LabelQuantity"
IsVisible="{Binding ShowQuantityColumn}"
/>
<Label
Grid.Row="0"
Grid.Column="3"
Text="Date"
x:Name="LabelDate"
IsVisible="{Binding ShowDateRaisedColumn}"/>
<Label
Grid.Row="0"
Grid.Column="4"
Text="Extension"
x:Name="LabelExtension"
IsVisible="{Binding ShowExtensionColumn}"/>
<ListView
Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="{Binding NumberOfVisibleColumns}"
x:Name="ListViewTransactionHistory">
<ListView.ItemTemplate >
<DataTemplate x:DataType="models:History" >
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label
Grid.Column="0"
Text="{Binding TransactionNumber}"
IsVisible="{Binding??? }"/> --- How do I access ShowTransactionNumber field here?
<Label Grid.Row="0"
Grid.Column="1"
Text="{Binding Description}" />
<Label
Grid.Column="2"
Text="{Binding Quantity}" />
<Label
Grid.Column="3"
Text="{Binding DateRaised}" />
<Label
Grid.Column="4"
Text="{Binding FormattedExtension}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
My Model is like this
public class TransactionHistory
{
public bool ShowTransactionNumberColumn { get; set; }
public bool ShowDescriptionColumn { get; set; }
public bool ShowQuantityColumn { get; set; }
public bool ShowDateRaisedColumn { get; set; }
public bool ShowExtensionColumn { get; set; }
public int NumberOfVisibleColumns {
get
{
int numberOfVisibleColumns = 0;
if (ShowTransactionNumberColumn) numberOfVisibleColumns++;
if (ShowDescriptionColumn) numberOfVisibleColumns++;
if (ShowQuantityColumn) numberOfVisibleColumns++;
if (ShowDateRaisedColumn) numberOfVisibleColumns++;
if (ShowExtensionColumn) numberOfVisibleColumns++;
return numberOfVisibleColumns;
}
}
public List<History> TransactionHistories { get; set; }
}
My History class is like this
public class History
{
public string TransactionNumber { get; set; }
public string Description { get; set; }
public decimal Quantity { get; set; }
public string DateRaised { get; set; }
public decimal Extension { get; set; }
public string FormattedExtension { get; set; }
}
My question is how do I bind the Transaction History model to view so that my list view is initialised with TransactionHistories. And How can I access the boolean variables inside the cell to toggle visibility of an element inside a cell?
In the code behind I can set the source of list view like this. But I won't be able to access the booleans.
ListViewTransactionHistory.ItemsSource = transactionHistory.TransactionHistories;
I think I am doing something wrong. Any idea will be helpful. Many Thanks :)
Edit:
On the code behind OnAppearing method I am doing this
protected override void OnAppearing()
{
TransactionHistoryStore transactionHistoryStore = new TransactionHistoryStore();
TransactionHistory transactionHistory = transactionHistoryStore.GetTransactions();
if (transactionHistory == null) return;
LabelTranNumber.IsVisible = transactionHistory.ShowTransactionNumberColumn;
LabelDescription.IsVisible = transactionHistory.ShowDescriptionColumn;
LabelDate.IsVisible = transactionHistory.ShowDateRaisedColumn;
LabelExtension.IsVisible = transactionHistory.ShowExtensionColumn;
// NumberOfVisibleColumns = numberOfVisibleColumns;
ListViewTransactionHistory.ItemsSource = transactionHistory.TransactionHistories;
}
So instead of setting IsVisible property manually. How can I bind the transactionHistory variable.
The transactionHistoryVariable is like this
public TransactionHistory GetTransactions()
{
TransactionHistory transaction = new TransactionHistory
{
ShowDescriptionColumn = true,
ShowQuantityColumn = true,
ShowDateRaisedColumn = true,
ShowExtensionColumn = true,
ShowTransactionNumberColumn = true,
TransactionHistories = new List<History>
{
new History
{
DateRaised = DateTime.Now.ToShortDateString(),
Description = "SMITH CHIPS ",
Extension = 2.25M,
FormattedExtension = 2.25.ToString("C"),
Quantity = 2,
TransactionNumber = "1234"
},
new History
{
DateRaised = DateTime.Now.ToShortDateString(),
Description = "SMITH CHIPS ",
Extension = 2.25M,
FormattedExtension = 2.25.ToString("C"),
Quantity = 2,
TransactionNumber = "1234"
},
new History
{
DateRaised = DateTime.Now.ToShortDateString(),
Description = "SMITH CHIPS ",
Extension = 2.25M,
FormattedExtension = 2.25.ToString("C"),
Quantity = 2,
TransactionNumber = "1234"
}
}
};
return transaction;
}
If I understood your question.
In your XAML set up the ListView ItemsSource={Binding TransactionHistories} (Looks like you already set the binding of the page)
In order you access the page binding, you have to use this small
binding trick:
Set up an x:Name for your parent ContentPage
In the element you want to hide, add this: {Binding Source={x:Reference NameOfPage}, Path=BindingContext.NameOfProperty}
More about it Here

How to dynamically generate GridLayout to contain Button and data

Have no clue as to how to handle this scenario dynamically after(2)
1) the app call the REST Json web service
2) Deserialize the Json response
3) Bind the Data to ListView
below is the working example.
Problem : I need to add a button to each row of record. Example , How to add a button next to Johnny Depp?? Add EventHandler for this button?
This means I need to dynamically generate the XAML? How to bind ?
here to code to handle the Returned Json Result:
-- Model:
public class Phone
{
public string mobile { get; set; }
public string home { get; set; }
public string office { get; set; }
}
public class Contact
{
public string id { get; set; }
public string name { get; set; }
public string email { get; set; }
public string address { get; set; }
public string gender { get; set; }
public Phone phone { get; set; }
}
public class ContactList
{
public List<Contact> contacts { get; set; }
}
---- Call REST
var client = new System.Net.Http.HttpClient();
var response = await client.GetAsync("http://Rest api");
string contactsJson = response.Content.ReadAsStringAsync().Result;
ContactList ObjContactList = new ContactList();
if (contactsJson != "")
{
ObjContactList = JsonConvert.DeserializeObject<ContactList>(contactsJson);
}
listviewConacts.ItemsSource = ObjContactList.contacts;
------XAML:
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Margin="10" Text="Display Json Data" FontSize="25" />
<ListView x:Name="listviewConacts" Grid.Row="1" HorizontalOptions="FillAndExpand" HasUnevenRows="True" ItemSelected="listviewContacts_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid HorizontalOptions="FillAndExpand" Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Text="{Binding name}" HorizontalOptions="StartAndExpand" Grid.Row="0" TextColor="Blue" FontAttributes="Bold"/>
<Label Text="{Binding email}" HorizontalOptions="StartAndExpand" Grid.Row="1" TextColor="Orange" FontAttributes="Bold"/>
<Label Text="{Binding phone.mobile}" HorizontalOptions="StartAndExpand" Grid.Row="2" TextColor="Gray" FontAttributes="Bold"/>
<BoxView HeightRequest="2" Margin="0,10,10,0" BackgroundColor="Gray" Grid.Row="3" HorizontalOptions="FillAndExpand" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
<ActivityIndicator x:Name="ProgressLoader" IsRunning="True"/>
</Grid>
Thanks
You created custom cell already, add button to it with Command and CommandParameter. Inside your viewcell grid add
<Button Text="Toggle" Command="{Binding Source={x:Reference YourPage}, Path=BindingContext.TapCommand}" CommandParameter="{Binding}"/>
Then in your model
public Command TapCommand
{
get
{
return new Command( (obj) =>
{
//obj here will be your data record
});
}
}

Databind my Accordion control in Silverlight 4

I have been searching all over the web trying to find an example of databinding an Accordion control.
I have written a simple test app to try and databind, and I can get the headers to bind, but can't seem to figure out how to get the content to bind. Could someone help me out?
Here is my XAML:
<tk:Accordion HorizontalAlignment="Left" Margin="12,12,0,0" Name="accordion1" Width="181" Height="325" Background="White" VerticalAlignment="Top">
<tk:Accordion.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding MenuHeaderName}" />
</StackPanel>
</DataTemplate>
</tk:Accordion.ItemTemplate>
<tk:Accordion.ContentTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=MenuItems.MenuItemName}" />
</StackPanel>
</DataTemplate>
</tk:Accordion.ContentTemplate>
</tk:Accordion>
And here is my code behind:
public partial class MainPage : UserControl
{
public class MenuItem
{
public MenuItem(string name) { MenuItemName = name; }
public string MenuItemName { get; set; }
}
public class MenuHeader
{
public MenuHeader(string name)
{
MenuItems = new List<MenuItem>();
MenuHeaderName = name;
}
public string MenuHeaderName { get; set; }
public List<MenuItem> MenuItems { get; set; }
}
public MainPage()
{
InitializeComponent();
List<MenuHeader> menuHeaders = new List<MenuHeader>();
MenuHeader robots = new MenuHeader("Robots");
robots.MenuItems.Add(new MenuItem("Robots - Item 1"));
robots.MenuItems.Add(new MenuItem("Robots - Item 2"));
robots.MenuItems.Add(new MenuItem("Robots - Item 3"));
menuHeaders.Add(robots);
MenuHeader pirates = new MenuHeader("Pirates");
pirates.MenuItems.Add(new MenuItem("Pirates - Item 1"));
pirates.MenuItems.Add(new MenuItem("Pirates - Item 2"));
pirates.MenuItems.Add(new MenuItem("Pirates - Item 3"));
menuHeaders.Add(pirates);
accordion1.ItemsSource = menuHeaders;
}
}
Figured it out.
Here is the XAML that works...
<tk:Accordion HorizontalAlignment="Left" Margin="12,12,0,0" Name="accordion1" Width="181" Height="325" Background="White" VerticalAlignment="Top">
<tk:Accordion.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding MenuHeaderName}" />
</StackPanel>
</DataTemplate>
</tk:Accordion.ItemTemplate>
<tk:Accordion.ContentTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding MenuItems}" BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding MenuItemName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</tk:Accordion.ContentTemplate>
</tk:Accordion>

Resources