Reputation: 4809
I am confused with how Xamarin binding works.
OneWay
Indicates that the binding should only propagate changes from source (usually the View Model) to target (the BindableObject). This is the default mode for most BindableProperty values.
So by default, if the values are set in the view model it will be reflected in the xaml pages.
But in the Xamarin default template, below is the code to insert a new item. Page doesn't have any two way binding mode set in the markup.
<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="Christianity.Mobile.Views.NewItemPage"
Title="New Item">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Cancel" Clicked="Cancel_Clicked" />
<ToolbarItem Text="Save" Clicked="Save_Clicked" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout Spacing="20" Padding="15">
<Label Text="Text" FontSize="Medium" />
<Entry Text="{Binding Item.Text}" d:Text="Item name" FontSize="Small" />
<Label Text="Description" FontSize="Medium" />
<Editor Text="{Binding Item.Description}" d:Text="Item description" FontSize="Small" Margin="0" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
Here I can see that default values of item are populated when a new page is created and also, edited name and description are available while saving the item.
My question - is two way binding implemented by default without having any binding mode set?
public partial class NewItemPage : ContentPage
{
public Item Item { get; set; }
public NewItemPage()
{
InitializeComponent();
Item = new Item
{
Text = "Item name",
Description = "This is an item description."
};
BindingContext = this;
}
async void Save_Clicked(object sender, EventArgs e)
{
MessagingCenter.Send(this, "AddItem", Item);
await Navigation.PopModalAsync();
}
async void Cancel_Clicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
}
UPDATE Here is my code to load data asynchronously
<?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="Christianity.Mobile.Views.ItemDetailPage"
Title="{Binding Title}">
<StackLayout Spacing="20" Padding="15">
<Label Text="Text:" FontSize="Medium" />
<Label Text="{Binding Item.Title}" d:Text="Item title" FontSize="Small"/>
<Label Text="Description:" FontSize="Medium" />
<Label Text="{Binding Item.Description}" d:Text="Item description" FontSize="Small"/>
</StackLayout>
</ContentPage>
public class ItemDetailViewModel : BaseViewModel
{
public ItemListItemDTO SelectedItem { get; set; }
public ItemDTO Item { get; set; }
public ICommand LoadItemCommand;
public ItemDetailViewModel(IPageService pageService, ItemListItemDTO selectedItem)
{
SelectedItem = selectedItem;
LoadItemCommand = new Command(async () => await LoadItem());
}
public async Task LoadItem()
{
IsBusy = true;
try
{
// Both are not working
Item = await ItemsDataStore.GetItemAsync(SelectedItem.Id);
//await Device.InvokeOnMainThreadAsync(async () =>
//{
// Item = await ItemsDataStore.GetItemAsync(SelectedItem.Id);
//});
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
}
Upvotes: 0
Views: 3745
Reputation: 10346
According to Xamarin.Forms Binding Mode, you can see that most bindable properties have a default binding mode of OneWay but the following properties have a default binding mode of TwoWay:
Date property of DatePicker
Text property of Editor, Entry, SearchBar, and EntryCell
IsRefreshing property of ListView
SelectedItem property of MultiPage
SelectedIndex and SelectedItem properties of Picker
Value property of Slider and Stepper
IsToggled property of Switch
On property of SwitchCell
Time property of TimePicker
These particular properties are defined as TwoWay for a very good reason:
When data bindings are used with the Model-View-ViewModel (MVVM) application architecture, the ViewModel class is the data-binding source, and the View, which consists of views such as Slider, are data-binding targets. MVVM bindings resemble the Reverse Binding sample more than the bindings in the previous samples. It is very likely that you want each view on the page to be initialized with the value of the corresponding property in the ViewModel, but changes in the view should also affect the ViewModel property.
The properties with default binding modes of TwoWay are those properties most likely to be used in MVVM scenarios.
Update:
For example, you get data using Web Api, then loading into ItemDTO Item, please comfirm that you have implement INotifyPropertyChanged interface for ItemDTO class to notify data changed.
public class ItemDTO:ViewModelBase
{
private string _Text;
public string Text
{
get { return _Text; }
set
{
_Text = value;
RaisePropertyChanged("Text");
}
}
private string _Description;
public string Description
{
get
{ return _Description; }
set
{
_Description = value;
RaisePropertyChanged("Description");
}
}
}
The ViewModelBase is the class that implement INotifyPropertyChanged.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Upvotes: 1