I am developing an application in .NET MAUI and i have a page with a collection view which is loaded with data. I display the data onto the collection view children. But then i have a problem, I have a stepper and i want when i change the stepper value, the label i named priceLabel to also change in this format (priceLabelValue = new stepper value * price of the current displayed item of collection view). I also have another label outside the collection view and i want to display on it the total price of all items in the collection view.
I have tried all ways i think but all in vain, one of the problems i encountered was that i was unable to access the views i created within the collection view from the code behind.
When i tried to update these children views using the view model i also found out that i could not access the current item of collection view from the view model.
HINT: Am developing a cart page for products.... Hope this will also help
This is my code.
// xaml code
<CollectionView x:Name="collcn"
ItemsSource="{Binding ShoppingBagCollection}"
Grid.Row="1"
Grid.ColumnSpan="2"
EmptyView="NO ITEMS ADDED">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:Cloth">
<Grid Padding="0"
Grid.ColumnDefinitions="*,*"
Grid.RowDefinitions="*,*,*"
ColumnSpacing="10"
HeightRequest="160"
HorizontalOptions="FillAndExpand"
Margin="20,20,0,20">
<Frame Grid.Column="0"
Grid.RowSpan="3"
Style="{StaticResource CardView}"
Margin="30"
HorizontalOptions="Start"
IsClippedToBounds="True">
<Image Source="{Binding Image}"
Aspect="Fill"
HeightRequest="100"
WidthRequest="100"/>
</Frame>
<VerticalStackLayout Grid.Column="1"
Grid.RowSpan="3"
Spacing="5"
HorizontalOptions="Start"
Margin="0,20,20,0">
<Label Text="{Binding Name}"
Style="{StaticResource MediumLabel}"
Grid.Row="0"/>
<!-- This label displays current value of stepper-->
<Label x:Name="stepperValue"
Style="{StaticResource MediumLabel}"
Text="{Binding Source={x:Reference stepper}, Path=Value}"/>
<Stepper x:Name="stepper"
Grid.Row="1"
Minimum="1"
Maximum="{Binding Quantity}"
Increment="1"/>
<!-- This label should display current value of stepper * Price of current Item-->
<Label x:Name="price"
Style="{StaticResource MediumLabel}"
Grid.Row="2"
Text="{Binding Price}"/>
</VerticalStackLayout>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Grid
Grid.ColumnSpan="2"
Grid.Row="2"
Padding="0"
Grid.ColumnDefinitions="*,*"
Grid.RowDefinitions="*,*,*,*"
ColumnSpacing="0"
HorizontalOptions="FillAndExpand"
Margin="20">
<VerticalStackLayout
Grid.RowSpan="4"
Grid.Column="0">
<!-- This entry should display total price of all items in collection view but i have failed to get a walk around-->
<Entry x:Name="totalcostLabel"
Grid.Row="2"
Placeholder="$0.00"
Margin="0,30,0,0"
Text="{Binding Source={x:Reference collcn}}"
WidthRequest="120"
HorizontalOptions="Start"
IsReadOnly="True"
Style="{StaticResource MediumLabel}"/>
<Label Grid.Row="2"
Text="TotalCost"
Margin="0"/>
</VerticalStackLayout>
// view model I think there is no need to post the view model and code behind because there is no special logic i have added after trying on so many different ways.
Any body to help me and tell me how l can go about that many thanks in advance.
CodePudding user response:
I've tried to reproduce your issue based on your code and found a solution to make it, though there might be other solutions. Try the following code:
First, in your .xaml file, for your stepper add a ValueChanged event, that's stepper_ValueChanged, which would be triggered while the value of stepper changes.
<Stepper x:Name="stepper"
Grid.Row="1"
Minimum="1"
Maximum="{Binding Quantity}"
Increment="1"
ValueChanged="stepper_ValueChanged"/>
Then, in .cs file, we generate a stepper_ValueChanged (or automatically generated by vs).
MainPageViewModel vm;
public MainPage()
{
InitializeComponent();
vm = new MainPageViewModel();
this.BindingContext = vm;
}
private void stepper_ValueChanged(object sender, ValueChangedEventArgs e)
{
double pricetotal = 0;
// The BindingContext of each stepper is Cloth instance in ObservableCollection.
//So here we go through every instance to find which one this stepper is related to.
var stepper = (Stepper)sender;
foreach (Cloth cloth in vm.ShoppingBagCollection)
{
if(cloth == stepper.BindingContext)
{
cloth.Price = cloth.Price / e.OldValue * e.NewValue;
}
pricetotal = cloth.Price;
}
vm.PriceTotal = pricetotal; // // the total price shown in the entry, we will define it later in ViewModel. It also changes while stepper changes.
}
In your Model Cloth, also make some changes. You should implements INotifyPropertyChanged and PropertyChanged event. For more information about INotifyPropertyChanged, you could refer to ViewModels and Property-Change Notifications
public class Cloth : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public double _price;
public double Price
{
get
{
return _price;
}
set
{
_price = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Price)));
}
}
......
}
Finally, in ViewModel, define a new property PriceTotal to which entry binds and also implememt the INotifyPropertyChanged.
public class MainPageViewModel :INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private double _priceTotal;
public double PriceTotal
{
get
{
return _priceTotal;
}
set
{
_priceTotal = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PriceTotal)));
}
}
.......
}
This is the main structure of my solution although I know there should be more details.
Hope my answer could help you.