How do I write xaml to bind (in MAUI) to a field other than the one specified in ItemsSource of the CollectionView? - xaml

I have this (probably naïve question):
I have this xaml:
<CollectionView
ItemsSource="{Binding Receipts}"
SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:Receipt">
<Grid Padding="1, 1, 1, 1">
<Frame Style="{StaticResource CardView}">
<Frame.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:ER_Expense_Receipts_View_VM}}, Path=GoToReceiptDetailsCommand}"
CommandParameter="{Binding .}" />
</Frame.GestureRecognizers>
<Grid RowDefinitions="Auto, *" ColumnDefinitions="310, 20" RowSpacing="10">
<Image
x:Name="imgReceipt"
Aspect="AspectFit"
Margin="0"
Grid.ColumnSpan="2"
Source="{Binding ContentsThumbnail, Mode=OneWay, Converter={StaticResource ByteArrayToImageSourceConverter}}"
WidthRequest="300" />
<Label
Grid.Row="1"
FontSize="12"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
VerticalOptions="Start"
VerticalTextAlignment="Center"
HeightRequest="30"
Text="{Binding Description}">
</Label>
<ImageButton
x:Name="cmdDelete"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:ER_Expense_Receipts_View_VM}}, Path=DeleteReceiptCommand}"
CommandParameter="{Binding ID}"
Grid.Row="1"
Grid.Column="1"
Source="delete2.svg"
HeightRequest="20"
WidthRequest="40">
<ImageButton.Triggers>
<DataTrigger TargetType="ImageButton" Binding="{Binding ExpenseReport.Status}" Value="{x:Static res:AppRes.StatusSent}">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="TextColor" Value="Gray" />
</DataTrigger>
</ImageButton.Triggers>
</ImageButton>
</Grid>
</Frame>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Receipts is a collection of Receipt objects in my "ER_Expense_Receipts_View_VM" model:
[ObservableProperty]
private Receipt receipt;
public ObservableCollection<Receipt> Receipts { get; } = new();
Also in my model I have this property
[ObservableProperty]
private Expense expense;
What I need to do here is to bind the "cmdDelete" ImageButton's property IsEnabled to the Status field of the ExpenseReport object in the model. See below. Alas, I get the message "Member not found in data context 'Receipt'".
So, please, what I am doing wrong here ? What's the correct syntax to bind that IsEnabled property to some field in the model other than from the Receipt objects ?
Thank you very much,
Alex

Related

CollectionView working in debug but not in release in .NET MAUI

I have the following
<CollectionView Margin="5" ItemsSource="{Binding Subjects}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="2" />
</CollectionView.ItemsLayout>
<CollectionView.EmptyView>
<ContentView>
<Label Text="No subjects entered yet..." />
</ContentView>
</CollectionView.EmptyView>
<CollectionView.ItemTemplate>
<DataTemplate>
<Border MaximumWidthRequest="300">
<Border.StrokeShape>
<RoundRectangle CornerRadius="10" />
</Border.StrokeShape>
<Border.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type vm:MainPageViewModel}}, Path=DeleteSubjectCommand}" CommandParameter="{Binding .}" />
</Border.GestureRecognizers>
<Label Margin="5" Text="{Binding .}" />
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
The problem is that the <Label Margin="5" Text="{Binding .}" /> is blank in release in my .NET MAUI Android application while in debug, it is populated and the gesture recogniser works.
When I add items to the list, the correct number of items appears so it leads me to think that there is something happening with the label highlighted above.
How do I solve this?
Replace:
<DataTemplate>
With:
<DataTemplate x:DataType="{x:Type x:String}>
Do not ask me why.

Trigger IsVisible true- false of label on radio button checked- Uncheck in xaml

I am trying to show/hide a label using Trigger on RadioButton check/uncheck but I am getting the error. I can also do it in c# code by inotifypropertychanged but i want to use Triggers and this is my first time. I am not able to understand this error.
<StackLayout Orientation="Vertical" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" Padding="10">
<Frame HasShadow="False" Margin="10,20" CornerRadius="5" BorderColor="{StaticResource BorderColor}" BackgroundColor="#F7F7F7">
<Grid HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<RadioButton Content="English" x:Name="rdbEnglish" HorizontalOptions="FillAndExpand" BackgroundColor="Transparent"
CornerRadius="10" BorderWidth="2" Margin="2"
Grid.Column="0" Grid.Row="0" IsChecked="{Binding IsCheckedEnglish,Mode=TwoWay}" >
</RadioButton>
<RadioButton Content="hindi" x:Name="rdbHindi" HorizontalOptions="FillAndExpand"
BackgroundColor="Transparent"
CornerRadius="10" BorderWidth="2" IsChecked="{Binding IsCheckedHindi,Mode=TwoWay}"
Margin="2" Grid.Column="1" Grid.Row="0" />
</Grid>
</Frame>
<StackLayout Orientation="Vertical" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" Padding="10">
<Label x:Name="lblrdbEnglish" Text="Note : Menu iteam changes will be updated next time"
Margin="2,-10,2,5" TextColor="Red" IsVisible="false" FontAttributes="Italic" >
<Label.Triggers>
<DataTrigger TargetType="RadioButton"
Binding="{Binding Source={x:Reference rdbEnglish},Path=IsChecked}" Value="True" >
<Setter Property="IsVisible" Value="True" />
</DataTrigger>
</Label.Triggers>
</Label>
</StackLayout>
</StackLayout>
Error
System.InvalidOperationException: 'bindable not an instance of AssociatedType'
The TargetType should be of type Label and not RadioButton.
From triggers docs:
TargetType - the control type that the trigger applies to.
...
<Label.Triggers>
<DataTrigger TargetType="Label"
Binding="{Binding Source={x:Reference rdbEnglish},
Path=IsChecked}" Value="True">
<Setter Property="IsVisible" Value="True" />
</DataTrigger>
</Label.Triggers>

How to access element in Xamarin Forms Expander by name?

I'm using the xamarin extended toolkit to show some Expanders in my application. What I'm trying to do is access an element in my Expander.ContentTemplate by setting x:Name. However when I try to access the element in my code-behind it doesn't find anything. What is the correct way to access any Label/Entry/Picker by name so I can manipulate it in the code-behind?
<xct:Expander Margin="0,0,0,20">
<xct:Expander.Header>
<Grid>
<Label FontAttributes="Bold" Text="Bookings" FontSize="Medium"/>
<Image Source="expand.png" HorizontalOptions="End"
VerticalOptions="Start">
<Image.Triggers>
<DataTrigger TargetType="Image"
Binding="{Binding Source={RelativeSource AncestorType={x:Type xct:Expander}}, Path=IsExpanded}"
Value="True">
<Setter Property="Source"
Value="collapse.png" />
</DataTrigger>
</Image.Triggers>
</Image>
</Grid>
</xct:Expander.Header>
<xct:Expander.ContentTemplate>
<DataTemplate>
<StackLayout Margin="0,10">
<Label x:Name="LabelDefaultPickup" FontAttributes="Bold" Text="Default Pickup location"/>
<Picker x:Name="PickupPicker" ItemsSource="{Binding ActivePickupList, Source={ x:Reference profilePage}}" ItemDisplayBinding="{Binding naam}" SelectedIndexChanged="PickupPicker_SelectedIndexChanged"/>
<Label x:Name="LabelDefaultPickupTime" FontAttributes="Bold" Text="Default Pickup time"/>
<Entry x:Name="DefaultPickupTime" Placeholder="pickup time" Text="{Binding Path=uurHeen}"/>
<Label x:Name="LabelDefaultDeparture" FontAttributes="Bold" Text="Default work location"/>
<Entry x:Name="DefaultDeparture" Placeholder="Location id" Text="{Binding Path=corp_id}"/>
<Label x:Name="LabelDefaultDepartureTime" FontAttributes="Bold" Text="Default Departure time"/>
<Entry x:Name="DefaultDepartureTime" Placeholder="Location id" Text="{Binding Path=uurTerug}"/>
</StackLayout>
</DataTemplate>
</xct:Expander.ContentTemplate>
</xct:Expander>
After reading the docs again, I removed the ContentTemplate tags (content is only rendered when the expander is tapped for the first time) after this change I could access an element like this:
var picker = BookingExpander.FindByName("PickupPicker") as Picker;
if (picker != null)
{
//do whatever you want
}

Sending SelectedIndex of ListView to ViewModel through CommandParameter

after a quite bit of googling I haven't found answer on this problem.
I have this ListView
<ListView x:Name="itemListView" ItemsSource="{Binding History}" HorizontalAlignment="Stretch">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Border Style="{StaticResource Border}" Background="{ThemeResource GradientLinear}" HorizontalAlignment="Stretch">
<Grid>
<StackPanel Orientation="Vertical" Margin="10,10,10,10" HorizontalAlignment="Left" Grid.Row="0" Grid.Column="0">
<TextBlock Text="{Binding name}" />
<TextBlock Text="{Binding question}" TextWrapping="Wrap"/>
<TextBlock Text="{Binding vrijeme}"/>
</StackPanel>
<Button Width="50" Height="50" Opacity="0.6" Grid.Row="0" Grid.Column="1" Tag="{Binding name}"
Command="{Binding ElementName=itemListView, Path=DataContext.Delete}" CommandParameter="{Binding ElementName=itemListView, Path=SelectedIndex}"
HorizontalAlignment="Right">
<SymbolIcon
HorizontalAlignment="Center"
Width="48"
Height="48"
Symbol="Delete" />
</Button>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Problem is probably in this part of the code
<Button Width="50" Height="50" Opacity="0.6" Grid.Row="0" Grid.Column="1" Tag="{Binding name}"
Command="{Binding ElementName=itemListView, Path=DataContext.Delete}" CommandParameter="{Binding ElementName=itemListView, Path=SelectedIndex}"
HorizontalAlignment="Right">
When I click Button, ListViewItem that contains that Button is not selected so I get -1 for SelectedIndex or just null if I target SelectedItem. It seems that clicking that button leaves containing ListViewItem unaffected. If I first click ListViewItem and than click button it works, SelectedItem is set in ListView of course, but I can't count user will understand that. My question is - is there any way to "force" Button to send me in CommandArgument SelectedItem or SelectedIndex. I know how to do that through code-behind but I am interested in solving this problem through MVVM.
Thanx in advance.

Bind BackgroundColor of a view inside DataTemplate Xamarin.Forms

I have a list view with a DataTemplate and inside it I have a StackLayout that I need set its background but the color of it is inside a variable...When I programmatically set the background of an object using this variable color it works, but when I try to use "binding" in xaml it doesn't work and I can't get this stack programmatically because it's inside a data template...
I really need your answer..
Some help?
<ListView.ItemTemplate>
<DataTemplate>
<!--<DataTemplate.Triggers>
<DataTrigger Binding="{Binding fundoColor}" Value="4">
<Setter TargetName="produtos_stack_color" Property="Background" Value="LawnGreen" />
</DataTrigger>
</DataTemplate.Triggers>-->
<ViewCell>
<StackLayout x:Name="produtos_stack_color" BackgroundColor="{Binding fundoColor}" VerticalOptions="FillAndExpand" Margin="10,10,10,10">
<StackLayout Orientation="Horizontal" Padding="10,10,10,10" BackgroundColor="Black" HorizontalOptions="FillAndExpand">
<Image Source="{Binding imagem}" HeightRequest="80" HorizontalOptions="CenterAndExpand" WidthRequest="160" Aspect="Fill"/>
<StackLayout Orientation="Horizontal" BackgroundColor="Green" VerticalOptions="Center" HorizontalOptions="CenterAndExpand">
<Label Style="{StaticResource labelsfont}" Text="R$" FontSize="Medium" TextColor="White"/>
<Label Style="{StaticResource labelsfont}" Text="{Binding valor}" FontAttributes="Bold" FontSize="Large" TextColor="White"/>
</StackLayout>
</StackLayout>
<StackLayout Margin="0,0,0,10">
<Label Text="{Binding nome}" Style="{StaticResource labelsfont}" FontAttributes="Bold" FontSize="Medium" TextColor="White" VerticalOptions="StartAndExpand" HorizontalOptions="Center"/>
<ContentView BackgroundColor="Chartreuse" HorizontalOptions="FillAndExpand">
<Label Style="{StaticResource labelsfont}" Text="{Binding observacao}" TextColor="White" Margin="10,10,10,10" HorizontalOptions="Center" />
</ContentView>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
I heard about triggers...but I really don't know how it works exactly...
I need produtos_stack_color receive the color
My global variable in code behind...It is setted just in construct of my class
InitializeComponent();
fundoColor = Color.FromHex(this.categEscolhida.corFundo);
You can only bind with properties - so you will have to create a property in code-behind class.
public Color FundoColor { get { return fundoColor; } }
Secondly, in order to refer this property in XAML - you can use Reference extension, and specify parent as Source. For e.g.:
<StackLayout x:Name="produtos_stack_color"
BackgroundColor="{Binding FundoColor, Source={x:Reference ParentHost}}" ..>
And, make sure to set x:Name attribute in root node of your XAML. For e.g:
<ContentPage x:Name="ParentHost" .. />