Use current item in - xamarin.forms

I am a bit stuck and I havent been able to find a solution yet. I hope you guys can help.
I have a collectionView
<CollectionView ItemsSource="{Binding ItemList}"
x:Name="MediaStreamCollectionView"
SelectionMode="Single"
SelectionChanged="SelectionChanged">
.....
and inside this I have made a content-view, but I can't figure out how to get the current item, so I can bind that to a content view property.
<contentView:FavoriteButton MediaStreamItem="{Binding this}">
My ItemList is like this:
ObservableCollection<MediaStreamItem> ItemList { get; set; }
and my contentview property looks like this
public static readonly BindableProperty MediaProperty = BindableProperty.Create(nameof(MediaProperty), typeof(MediaStreamItem), typeof(FavoriteButton), new MediaStreamItem());
public MediaStreamItem MediaStreamItem
{
get => (MediaStreamItem) GetValue(FavoriteButton.MediaProperty);
set => SetValue(FavoriteButton.MediaProperty, value);
}
It works fine for all the properties on ItemList but not on the current Item-object.
Anyone know how I can solve this?

use "." for the current item
<contentView:FavoriteButton MediaStreamItem="{Binding .}">

Related

Applying filtering to ObservableCollection items without allocating additional memory for each filtered item

.Net Maui app. I want to have a SearchBar where user is able to enter search text and ListView or any other view with ItemsSource to react immediately by filtering out any not matched item. I do not want to re-create ObservableCollection of items each time user changes one single symbol in the search bar since it re-allocates memory for the filtered list of items, and the list could be long.
I've found how this handled by syncfuntion list control: https://help.syncfusion.com/maui/listview/filtering. Filter there applied "on the run" to each item in the list while binding it to the ItemsSource of a View, so no new collection is created for the search params, same collection is used but with different param on "per item" bases. You can achieve similar effect if you use IEnumerable with custom Where statement, but then you lost benefits of your collection being "observable". Any ideas on how to resolve this without syncfusion's listview control?
"Filter" by binding IsVisible of ItemTemplates view to a bool that you set.
<ListView.ItemTemplate>
<DataTemplate>
<SomeLayoutOrViewHere IsVisible="{Binding Show}" ...
...
public ObservableCollection<MyItem> MyItems ...
void ApplyFilter(...)
{
foreach (MyItem item in MyItems)
{
item.Show = ...;
}
}
public class MyItem : ObservableObject
{
public bool Show { get => show; set => SetProperty(ref show, value); }
private bool show;
...
}

Dynamically add Icons to titlebar Maui

Im creating an App where I want have multiple icons in my titlebar (they should be clickable). One Icon should be on the Left of the title text like so (this icon is static and will not change):
The other Icons should be on the right (these icons should be dynamic, as they will be used to alert the user if anything important happens):
I'm using a simple shell, so no Navigationpage, thus I don't think <NavigationPage.Titleview> can be used in this case. Is there any way to achieve something like this in Maui?
You can use the shell title view as stated in this answer, it is pointing to Xamarin documentation but it is also valid for MAUI.
In your case you will have something like this inside your AppShell.xaml :
<Shell.TitleView>
<Grid ColumnDefinitions="auto,*,auto">
<Label Text="Title" BackgroundColor="Red"></Label>
<HorizontalStackLayout Grid.Column="2">
<Label Text="Icon" BackgroundColor="Red"></Label>
</HorizontalStackLayout>
</Grid>
</Shell.TitleView>
Which look like this (very trendy design) :
How to update the icons can be done by data binding or creating directly the object from C# :
<HorizontalStackLayout Grid.Column="2" x:Name="IconsContainer">
<Label Text="Icon" BackgroundColor="Red" IsVisible="{Binding Icon1Visible}"></Label>
</HorizontalStackLayout>
And in the C# :
public partial class AppShell : Shell
{
public bool Icon1Visible { get; set; } = false;
public AppShell()
{
InitializeComponent();
// An object containing the binding data
BindingContext = this;
// Directly create a new icon
AddIcon();
// Show an icon through binding
ShowIcon();
}
public void ShowIcon()
{
Icon1Visible = true;
}
public void AddIcon()
{
var icon = new Label();
icon.Text = "And another one";
IconsContainer.Children.Add(icon);
}
}
To get whenever you want to update the icons I would go with dependency injection and either pass directly a view model to bind the icons on or using events.

How to change property value of a view inside CarouselView's ItemTemplate?

I have a CarouselView with ItemTemplate containing a Label and a Grid. Outside of that CarouselView, I want to make a button to modify Carousel's current item's Grid's visibility. Because it's inside ItemTemplate, I can't use x:Name to refer to that specific Grid, so how can I refer to the current item's Grid so I can change its property value? Thank you.
You will want to do that through databinding. As you already mentioned, you can't use x:Name. This is because you're inside of a template. The value in x:Name would be duplicated for each time that template is applied to a concrete item in your list, in this case a CarouselView. Moreover; if you use virtualization for that list, a template might not even exist at all at that point in time. All reasons why you can't use x:Name to reference anything inside of a template.
I don't have any info about the code you want to use this with, so I'll make something up.
If the backing collection for your CarouselView is a ObservableCollection<MyItem>, then your CarouselView might look something like this:
<!-- Databinding scope here is MyViewModel -->
<CarouselView ItemsSource="{Binding MyItemsCollection}">
<CarouselView.ItemTemplate>
<!-- Databinding scope here is MyItem -->
<DataTemplate>
<Button Text="Delete" IsVisible="{Binding CanDelete}" />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
So you will have a backing view model which has a MyItemsCollection, and your page (that holds the CarouselView) has set the BindingContext to a new instance of MyViewModel:
public class MyViewModel
{
public ObservableCollection<MyItem> MyItemsCollection { get; set; } = new ObservableCollection<MyItem>();
private void LoadData()
{
var items = _myItemService.GetItems();
foreach (var item in items)
{
MyItemsCollection.Add(item);
}
}
}
Whenever you want to influence the IsVisible you will want to set the CanDelete of the MyItem that it's about to false. Let's assume MyItem looks like this:
public class MyItem
{
public bool CanDelete { get; set; }
}
You will need to implement the INotifyPropertyChanged interface on it so that the UI will pick up on any changes that are made to property values.
Now whenever you set the CanDelete of a certain instance of MyItem to false, that will change your UI. E.g.: MyItemsCollection[3].CanDelete = false;
On my YouTube channel I added a playlist with videos about data binding which might help in cases like these.
PS. At the time of writing IsVisible is bugged in .NET MAUI

What's the best practice to disable a button in Xamarin.Forms, MvvmCross, when using Command?

I have some troubles in disabling a Button's Command in a Xamarin.Forms MvvmCross project. IsEnabled doesn't seem to work properly, even if using the CanExecute property.
On the yaml file of the page:
<Button Text="DoSomething" Command="{Binding DoSomethingCommand}" IsEnabled="{Binding DoSomethingIsEnabled}"/>
On the view model:
public IMvxCommand DoSomethingCommand => new MvxCommand(() => System.Diagnostics.Debug.WriteLine("Is enabled!"));
or
public IMvxCommand DeviceButtonCommand => new MvxCommand(() => System.Diagnostics.Debug.WriteLine("Is enabled!"), () => DoSomethingIsEnabled);
I read some posts about it but I haven't solved the problem yet, no idea?
I think you need to call a method on the command when you change the property specified in the CanExecute delegate.
Something like ChangeCanExecute() for XF.
And I don't remember the name for mvvmcross :)
EDITED: it's RaiseCanExecuteChanged for MvvmCross.
private bool _doSomethingIsEnabled;
public bool DoSomethingIsEnabled
{
get => _doSomethingIsEnabled;
set
{
_doSomethingIsEnabled = value;
DoSomethingCommand.ChangeCanExecute();
}
}

XF binding data from a popuppage to a contentpage through xaml

I have a popup page in my application which includes some checkboxes, and I also have a ContentPage in my MainPage which contains some stacklayouts, I want to bind the IsVisible Property of my stacklayout to the IsChecked property of my checkbox (which is in another page), but i don't know how to do it, can anybody please help?
I've tried this, but it doesn't work
here's the code in my popup page:
<StackLayout Orientation="Horizontal" Spacing="60">
<local:Checkbox x:Name="va1Checkbox" Text="VA1"/>
<local:Checkbox x:Name="va2Checkbox" Text="VA2"/>
</StackLayout>
and this is the piece of code i have in my MainPage:
<StackLayout IsVisible="{Binding Source={x:Reference
va1Checkbox},Path=IsChecked}">
</StackLayout>
Thanks in advance
<StackLayout Orientation="Horizontal" Spacing="60">
<local:Checkbox x:Name="va1Checkbox" Text="VA1"/>
<local:Checkbox x:Name="va2Checkbox" Text="VA2"/>
</StackLayout>
I believe your popup represents some kind of settings based on which you control your StackLayout in Main Page.
If this is the case, there are two possible solutions.
Create a separate class which is binding for both checkbox and layout. You can use this either with MVVM or without it.
Value Passing: open popup from Main Page and register to its close event. When popup is closed you can use its checkbox's value to enable/disable the layout.
In your Popup.xaml.cs :
create an event action
public event Action<Popup> OnClose;
I believe you will have a way to close it. I don't know you are closing it so I will just use OnBackButtonPressed() here:
protected override bool OnBackButtonPressed()
{
OnClose?.Invoke(this);
return base.OnBackButtonPressed();
}
In your MainPage.xaml.cs :
private void OpenPopup()
{
var popup = new PopupPage();
popup.OnClose += OnPopupClosed;
}
void OnPopupClosed(Popup popup)
{
yourStackLayout.IsVisible = popup.va1Checkbox.Value;
}
UPDATE:
You can pass custom data class instead of popup object:
public class PopupData
{
public bool va1CheckboxValue;
public bool va1CheckboxValue;
// other data which you need to access in other page.
}
then
public event Action<PopupData> OnClose;
and
protected override bool OnBackButtonPressed()
{
PopupData data = new PopupData() { va1CheckboxValue = va1Checkbox.Value; }
OnClose?.Invoke(data);
return base.OnBackButtonPressed();
}
and in main page:
void OnPopupClosed(PopupData data)
{
yourStackLayout.IsVisible = data.va1CheckboxValue;
}
Hope this helps.
I don't know very well XAML and MVVM, but I think you can pass MainPage's ViewModel to Popup... if you change MainPage's ViewModel properties in Popup I think these changes will reflect also to MainPage's binded controls.
If you are not using MVVM (you should...), I think you have to pass a reference to properties used in MainPage to Popup... in this way, Popup can change MainPage's properties and its UI could change

Resources