my problem is when I send an object of Order to my function, it comes Null without updating my values, how can I edit them?
I try to update my Object. I expecting get in my function Object of Order with the value and not null
here is my function that needs to get the Object.
[RelayCommand]
async Task Continue(Order order)
{
//Order order = new Order()
//{
// DateStart = dateStart,
// DateEnd = dateEnd,
// DogName = dogName
//};
await Shell.Current.GoToAsync(nameof(ShowOrderPage), true, new Dictionary<string, object>
{
{"Order", order}
});
}
using Pension.ViewsModels;
namespace Pension.View;
public partial class MainPage : ContentPage
{
public MainPage(MainViewModel vm)
{
InitializeComponent();
BindingContext = vm;//here the error
}
}
my XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:model="clr-namespace:Pension.Models"
xmlns:viewmodel="clr-namespace:Pension.ViewsModels"
x:DataType="viewmodel:MainViewModel"
x:Class="Pension.Views.MainPage"
BackgroundColor="#F2F2F2">
<VerticalStackLayout Margin="0,20,0,0" Spacing="10" FlowDirection="RightToLeft">
<Label Text="הזמנת פנסיון לכלב" FontSize="40" HorizontalOptions="Center" Margin="5"/>
<Label Text="לפני שנתחיל נשמח לדעת מה התאריך בו תרצו להתארח אצלנו" HorizontalOptions="Center" FontSize="20" FontFamily="op-light"/>
<Grid Padding="20" Background="#FFFFFF" Margin="54">
<Grid.Shadow>
<Shadow Brush="#000"
Offset="5,0"
Opacity="0.26"/>
</Grid.Shadow>
<VerticalStackLayout Spacing="10" x:DataType="model:Order">
<Label Text="בחירת תאריך" FontSize="30" HorizontalOptions="Center" Margin="0,0,0,15"/>
<Frame x:Name="DateStart" CornerRadius="0" Padding="10,0">
<DatePicker MinimumDate="01/01/2022"
MaximumDate="12/31/2025"
Date="{Binding DateStart}"/>
</Frame>
<Frame CornerRadius="0" Padding="10,0">
<DatePicker x:Name="DateEnd" MinimumDate="01/01/2022"
MaximumDate="12/31/2025"
Date="{Binding DateEnd}" />
</Frame>
<Frame CornerRadius="0" Padding="10,0">
<Entry x:Name="dogName" Placeholder="שם הכלב/ה" Text="{Binding DogName}"/>
</Frame>
<Button Text="המשך" BackgroundColor="#EEBF3E"
TextColor="Black" CornerRadius="0"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:MainViewModel}},Path=ContinueCommand}"
CommandParameter="{Binding Source={RelativeSource AncestorType={x:Type model:Order}}}">
<Button.Shadow>
<Shadow Brush="#ccccd0"
Offset="3,6"
Opacity="1"/>
</Button.Shadow>
</Button>
</VerticalStackLayout>
</Grid>
</VerticalStackLayout>
</ContentPage>
into the Entry, I try to insert my values and it's not working
why I need him in VM? I have a Model of Order, and I want to send the object to function after I updated the values of this order in the XMAL code.
You should not fully understand the meaning of BindingContext and MVVM.
From document Data Binding Basics,we know that:
Data bindings connect properties of two objects, called the
source
and thetarget
. In code, two steps are required: TheBindingContext
property of the target object must be set to the source object, and theSetBinding
method (often used in conjunction with theBinding
class) must be called on the target object to bind a property of that object to a property of the source object.The target property must be a bindable property, which means that the target object must derive from
BindableObject
. The online Xamarin.Forms documentation indicates which properties are bindable properties. A property of Label such asText
is associated with the bindable propertyTextProperty
Simply put, when you set the BindingContext = vm;
for your page(MainPage
), you usually
need to bind the properties(including simple types(e.g.string
, int
) or Object
) and command from the vm(Yours is MainViewModel
) instead of binding from other classes.
Based on your code, your MainViewModel
should code as follows:
MainViewModel.cs
public class MainViewModel
{
public Order order { get; set; }
public MainViewModel()
{
order = new Order { DateStart = "2022-11-16", DateEnd = "2022-11-17", DogName = "puppy" };
}
public ICommand ContinueCommand => new Command<Order>(continueItem);
private void continueItem(Order obj)
{
System.Diagnostics.Debug.WriteLine(" the passted Order's name is: " + obj.DogName);
}
}
Order.cs
public class Order: INotifyPropertyChanged
{
public string DateStart { get; set; }
public string DateEnd { get; set; }
//public string DogName { get; set; }
string _dogName;
public string DogName
{
get => _dogName;
set => SetProperty(ref _dogName, value);
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
TestPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiCollectionApp.TestPage"
xmlns:model="clr-namespace:MauiCollectionApp.model"
Title="TestPage">
<VerticalStackLayout Margin="0,20,0,0" Spacing="10" FlowDirection="RightToLeft">
<Label Text="הזמנת פנסיון לכלב" FontSize="40" HorizontalOptions="Center" Margin="5"/>
<Label Text="לפני שנתחיל נשמח לדעת מה התאריך בו תרצו להתארח אצלנו" HorizontalOptions="Center" FontSize="20" FontFamily="op-light"/>
<Grid Padding="20" Background="#FFFFFF" Margin="54">
<Grid.Shadow>
<Shadow Brush="#000"
Offset="5,0"
Opacity="0.26"/>
</Grid.Shadow>
<VerticalStackLayout Spacing="10" >
<Label Text="בחירת תאריך" FontSize="30" HorizontalOptions="Center" Margin="0,0,0,15"/>
<Frame x:Name="DateStart" CornerRadius="0" Padding="10,0">
<DatePicker MinimumDate="01/01/2022"
MaximumDate="12/31/2025"
Date="{Binding order.DateStart}"/>
</Frame>
<Frame CornerRadius="0" Padding="10,0">
<DatePicker x:Name="DateEnd" MinimumDate="01/01/2022"
MaximumDate="12/31/2025"
Date="{Binding order.DateEnd}" />
</Frame>
<Frame CornerRadius="0" Padding="10,0">
<Entry x:Name="dogName" Placeholder="שם הכלב/ה" Text="{Binding order.DogName}"/>
</Frame>
<Button Text="המשך" BackgroundColor="#EEBF3E"
TextColor="Black" CornerRadius="0"
Command="{Binding ContinueCommand}"
CommandParameter="{Binding order}">
<Button.Shadow>
<Shadow Brush="#ccccd0"
Offset="3,6"
Opacity="1"/>
</Button.Shadow>
</Button>
</VerticalStackLayout>
</Grid>
</VerticalStackLayout>
</ContentPage>
TestPage.xaml.cs
public partial class TestPage : ContentPage
{
public TestPage()
{
InitializeComponent();
this.BindingContext = new MainViewModel();
}
}
Note:
1.I defined a variable order
and added ICommand ContinueCommand
in ViewModel MainViewModel
.
then, we can bind as follows:
<DatePicker MinimumDate="01/01/2022"
MaximumDate="12/31/2025"
Date="{Binding order.DateStart}"/>
And add command for button like this:
<Button Text="המשך" BackgroundColor="#EEBF3E"
TextColor="Black" CornerRadius="0"
Command="{Binding ContinueCommand}"
CommandParameter="{Binding order}">
<Button.Shadow>
<Shadow Brush="#ccccd0"
Offset="3,6"
Opacity="1"/>
</Button.Shadow>
</Button>
2.I defined class Order
and implemented interface INotifyPropertyChanged
for it. Then if we change the value of DogName
, the value of variable order
in MainViewModel
will be updated.
public class Order: INotifyPropertyChanged
{
public string DateStart { get; set; }
public string DateEnd { get; set; }
//public string DogName { get; set; }
string _dogName;
public string DogName
{
get => _dogName;
set => SetProperty(ref _dogName, value);
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Update
I achieved this function with nuget CommunityToolkit.MVVM
, and it works on my side.
You can refer to the following code:
MyMainViewModel.cs
public partial class MyMainViewModel
{
public MyOrder order { get; set; }
public MyMainViewModel()
{
order = new MyOrder { DateStart = "2022-11-16", DateEnd = "2022-11-17", DogName = "puppy" };
}
[RelayCommand]
async Task Continue(MyOrder order)
{
System.Diagnostics.Debug.WriteLine(" the passted Order's name is: " + order.DogName);
}
}
MyOrder.cs
public partial class MyOrder: ObservableObject
{
[ObservableProperty]
private string? dateStart;
[ObservableProperty]
private string? dateEnd;
[ObservableProperty]
private string? dogName;
[RelayCommand]
async Task Continue(Order order)
{
System.Diagnostics.Debug.WriteLine(" the passted Order's name is: " + order.DogName);
}
}
TestPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiCollectionApp.TestPage"
xmlns:model="clr-namespace:MauiCollectionApp.model"
Title="TestPage">
<VerticalStackLayout Margin="0,20,0,0" Spacing="10" FlowDirection="RightToLeft">
<Label Text="הזמנת פנסיון לכלב" FontSize="40" HorizontalOptions="Center" Margin="5"/>
<Label Text="לפני שנתחיל נשמח לדעת מה התאריך בו תרצו להתארח אצלנו" HorizontalOptions="Center" FontSize="20" FontFamily="op-light"/>
<Grid Padding="20" Background="#FFFFFF" Margin="54">
<Grid.Shadow>
<Shadow Brush="#000"
Offset="5,0"
Opacity="0.26"/>
</Grid.Shadow>
<VerticalStackLayout Spacing="10" >
<Label Text="בחירת תאריך" FontSize="30" HorizontalOptions="Center" Margin="0,0,0,15"/>
<Frame x:Name="DateStart" CornerRadius="0" Padding="10,0">
<DatePicker MinimumDate="01/01/2022"
MaximumDate="12/31/2025"
Date="{Binding order.DateStart}"/>
</Frame>
<Frame CornerRadius="0" Padding="10,0">
<DatePicker x:Name="DateEnd" MinimumDate="01/01/2022"
MaximumDate="12/31/2025"
Date="{Binding order.DateEnd}" />
</Frame>
<Frame CornerRadius="0" Padding="10,0">
<Entry x:Name="dogName" Placeholder="שם הכלב/ה" Text="{Binding order.DogName}"/>
</Frame>
<Button Text="המשך" BackgroundColor="#EEBF3E"
TextColor="Black" CornerRadius="0"
Command="{Binding ContinueCommand}"
CommandParameter="{Binding order}">
<Button.Shadow>
<Shadow Brush="#ccccd0"
Offset="3,6"
Opacity="1"/>
</Button.Shadow>
</Button>
</VerticalStackLayout>
</Grid>
</VerticalStackLayout>
</ContentPage>
TestPage.xaml.cs
public partial class TestPage : ContentPage
{
public TestPage()
{
InitializeComponent();
//this.BindingContext = new MainViewModel();
this.BindingContext = new MyMainViewModel();
}
}