How to get selected item in Xamarin - xamarin

I have a Picker in Xamarin and I want to pass the selected item in Picker to the another page(TablePage). Below this Picker there is a button and whenever it is clicked I want to go to the other page and display the selected value in the pther page.
<Picker x:Name="SelectTablePicker" Title="Select table" TextColor="#676FA3" TitleColor="#676FA3" FontSize="Title" ItemsSource="{Binding TablesFromViewModelCollector}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding SelectedTable}" />
<Button x:Name="SelectTableButton" Text="Select Table" HorizontalOptions="Center" Style="{DynamicResource TitleStyle}" Clicked="Selected_Button" />
So how I am trying to pass this value is with click event:
async void Selected_Button(object sender, System.EventArgs e)
{
var SelectTablePicker = (Picker)sender;
int selectedIndex = SelectTablePicker.SelectedIndex;
if (selectedIndex != -1)
{
await Navigation.PushAsync(new TablePage((string)SelectTablePicker.ItemsSource[selectedIndex]));
}
}
And on the Table Page, I created Label where I want to show the selected item:
<Label x:Name="MyLabel" Text="#" HorizontalOptions="Fill" Grid.Column="0" BackgroundColor="#FF5959" TextColor="#EEF2FF" HorizontalTextAlignment="Left" Padding="0, 0, 0, 10" VerticalTextAlignment="Center"/>
And here its controller:
public TablePage(string tableName)
{
InitializeComponent();
MyLabel.Text = $"{UserName}";
}
But whenever I click the button I am getting an error and I couldnt figure out why.

this is a button click event, so the sender is a Button, not a Picker
var SelectTablePicker = (Picker)sender;
int selectedIndex = SelectTablePicker.SelectedIndex;
instead just do this
// SelectTablePicker is the name of your picker
int selectedIndex = SelectTablePicker.SelectedIndex;
and even better, you are already binding SelectedItem="{Binding SelectedTable}" so you could just get the value of SelectedTable directly from your VM
finally, you want to cast the selected item as a Table, not a string
new TablePage((Table)SelectTablePicker.ItemsSource[selectedIndex])

Related

How to update Preferences again after removing item to list in Xamarin

I have a list of CartUsers. I execute the command remove item from the list. I managed to remove each item in the list. However how does the list Preferences update.
My code:
cart.xaml
<StackLayout Padding="15,13" BindableLayout.ItemsSource="{Binding CartUsers}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout Margin="0,2.5" x:DataType="model:CartUser">
<Label Text="{Binding NumberProduct}" />
<ImageButton x:Name="removeitem" Clicked="removeitem_Clicked" >
<ImageButton.Source>
<FontImageSource Color="red" Size="10" FontFamily="FontAwesome" Glyph="{x:Static local:FontAwesomeClass.TrashAlt}"/>
</ImageButton.Source>
</ImageButton>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
2.cart.xaml.cs
CartUserViewModel cartUserViewModel;
private void removeitem_Clicked(object sender, EventArgs e)
{
var mycart = Preferences.Get("CartUser", "defaultcart");
var getcart = JsonConvert.DeserializeObject<List<CartUser>>(mycart);
var button = sender as ImageButton;
var itemcart = button.BindingContext as CartUser;
cartUserViewModel.RemoveItemCart.Execute(itemcart);
//Preferences.Set("CartUser", JsonConvert.SerializeObject(getcart));
}
Update...
private void removeitem_Clicked(object sender, EventArgs e)
{
var mycart = Preferences.Get("CartUser", "defaultcart");
var getcart = JsonConvert.DeserializeObject<List<CartUser>>(mycart);
var button = sender as ImageButton;
var itemcart = button.BindingContext as CartUser;
cartUserViewModel.RemoveItemCart.Execute(itemcart);
getcart.Remove(itemcart);
int count = getcart.Count();
Preferences.Set("CartUser", JsonConvert.SerializeObject(getcart));
}
You just deleted a CartUser inside the ViewModel, and the Preferences have not changed.
According to your code, getcart is the List obtained using Preferences. You need to use getcart.Remove(itemcart); to delete an item. Then use your commented code to store it.

How to know which indicator you are on with CarouselView in Xamarin Forms?

I a using the CarouselView and I can successfully load in items! Yey, so far so good. But now when i reach the 2nd item, I try to do a specific function that will only happen in the 2nd index.
Right now i seem to have figured out when im on the 2nd page al though the log is writing a lot of things in the log, but when i transition to the 3rd page, or back to the 1st page, i have lost count (programmatically) of where I am.
<CarouselView BackgroundColor="Transparent"
HorizontalScrollBarVisibility="Never"
IndicatorView="indicatorView"
VerticalOptions="CenterAndExpand"
Margin="25,0"
Scrolled="CarouselView_Scrolled"
ItemsSource="{Binding BindingContext.Intro, Source={x:Reference ParentView}}">
<CarouselView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal"
SnapPointsAlignment="Center"
SnapPointsType="MandatorySingle"/>
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Text}"
FontSize="Large"
HorizontalTextAlignment="Start"
FontFamily="Helvetica Neue"
TextColor="DimGray"
FontAttributes="None" />
</AbsoluteLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
Code behind:
async void CarouselView_Scrolled(System.Object sender, Xamarin.Forms.ItemsViewScrolledEventArgs e)
{
System.Diagnostics.Debug.WriteLine(e.CenterItemIndex);
if (e.CenterItemIndex == 1)
{
if (Transitioning == false)
{
Transitioning = true;
await ParentView.ColorTo(Color.White, Color.FromHex("#161825"), c =>
{
ParentView.BackgroundColor = c;
Transitioning = false;
}, 500);
}
}
else
{
Transitioning = true;
await ParentView.ColorTo(Color.FromHex("#161825"), Color.White, c => ParentView.BackgroundColor = c, 500);
Transitioning = false;
}
}
What logic do i need to add in my frontend to successfully monitor if im on page 2?
ItemsViewScrolledEventArgs has a CenterItemIndex property that tells you which item is in the center view
or you could use the CurrentItemChanged event

Passing data from list to new view xamarin

Ive created a picker with data inside, when selected the data is added to a list. I want to the values that are added to the list to follow to the next page when calculate button is pressed.. tried a few different approaches but i cant get it right..
.cs
// add from picker to listview function
ObservableCollection<LayersClass> listProducts = new ObservableCollection<LayersClass>();
private void MainPicker_SelectedIndexChanged(object sender, EventArgs e)
{
// feedback popup box
var product = MainPicker.Items[MainPicker.SelectedIndex];
DisplayAlert(product, "Layer added to calculation list", "OK");
// if selected add to list
if (null != product)
{
LayersClass layer = new LayersClass();
layer.Product = product;
listProducts.Add(layer);
}
}
//calculate button
private async void Button_Clicked(object sender, EventArgs e)
{
// send selected values to CalculationPage ??
await Navigation.PushAsync(new CalculationPage());
}
xaml:
<ListView
x:Name="productsListView"
HasUnevenRows="False"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
BackgroundColor="White">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Clicked="MenuItem_Clicked" Text="Delete" IsDestructive="true" CommandParameter="{Binding .}" />
</ViewCell.ContextActions>
<StackLayout>
<Label Text="{Binding Product}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Margin="0,0,0,90" Text="Calculate" Clicked="Button_Clicked" FontSize="Medium" TextColor="#00AB8E" HorizontalOptions="Center" BackgroundColor="Transparent"/>
You should use parameter to pass data to the another page.
private async void Button_Clicked(object sender, EventArgs e)
{
// send selected values to CalculationPage ??
//Also you should write there an event.
var item = sender as Button;
var selectedItem = item as LayersClass;
await Navigation.PushAsync(new CalculationPage(item));
}
public CalculationPage(string item){
//when you type here dot after typing item like this -> item. you can see the layerclass items.
}

HorizontalTextAlignment is ignored after navigation

I have created a simple app, where users can see more information in section, if they tab a Label, which is seen on the pictures below.
The problem is, that after navigating to AnotherPage and back, the text moves to left, even though I have set the HorizontalTextAlignment to End.
This only happens, when I have shown the section and hiding it again (by tapping on the Label twice).
The problem is illustrated on the picture below, where y is located at the left side.
My source code for showing a simple app with this problem, can be downloaded from this Dropbox link.
EDIT
Added code example
The ContentPage is as simple as
<StackLayout>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="Test" VerticalOptions="Start" />
<Label Text="{Binding Text}" HorizontalTextAlignment="End" TextColor="Red" HorizontalOptions="FillAndExpand" BackgroundColor="Yellow">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ChangeVisibilityCommand}" />
</Label.GestureRecognizers>
</Label>
</Grid>
<StackLayout IsVisible="{Binding IsVisible}">
<Label Text="Text 1" />
<Label Text="Text 2" />
</StackLayout>
<Button Command="{Binding OpenAnotherPageCommand}" Text="Open Another Page" />
</StackLayout>
And the ViewModel is shown below
public class MainPageViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ICommand _changeVisibilityCommand;
public ICommand ChangeVisibilityCommand
{
get => _changeVisibilityCommand;
set
{
if (value != _changeVisibilityCommand)
{
_changeVisibilityCommand = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ChangeVisibilityCommand)));
}
}
}
private bool _isVisible;
public bool IsVisible
{
get => _isVisible;
set
{
if (value != _isVisible)
{
_isVisible = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsVisible)));
}
}
}
private ICommand _openAnotherPageCommand;
public ICommand OpenAnotherPageCommand
{
get => _openAnotherPageCommand;
set
{
if (value != _openAnotherPageCommand)
{
_openAnotherPageCommand = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OpenAnotherPageCommand)));
}
}
}
private string _text = "u";
public string Text
{
get => _text;
set
{
if (!string.Equals(_text, value, StringComparison.InvariantCultureIgnoreCase))
{
_text = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Text)));
}
}
}
public MainPageViewModel()
{
ChangeVisibilityCommand = new Command(() =>
{
IsVisible = !IsVisible;
Text = IsVisible ? "x" : "y";
});
OpenAnotherPageCommand = new Command(() =>
{
(Application.Current.MainPage as NavigationPage)?.PushAsync(new AnotherPage());
});
}
}
And the AnotherPage is simply showing a text for example
First of all, i wasn't able to reproduce your issue using the latest version of Xamarin. Maybe simply upgrading Xamarin (Forms) will remove the unwanted behavior in your case as well.
If not, you have two options:
1 - Use HorizontalOptions instead
HorizontalOptions="EndAndExpand"
since HorizontalOptions has a higher priority in the layout engine.
Not the most elegant way but surely the most reliable.
2 - Use DataBinding
In your model just add the following property:
public TextAlignment LabelAlignment
{
get => labelAlignment;
set
{
labelAlignment = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(LabelAlignment)));
}
}
private TextAlignment labelAlignment = TextAlignment.End;
And in your Xaml you change HorizontalAlignment to
HorizontalTextAlignment="{Binding LabelAlignment}"
That will work because after your screen has been created, the values in the model will be loaded and updated afterwards.
Change HorizontalOptions="FillAndExpand"
To HorizontalOptions="CenterAndExpand"
This will force the text to expand from the center and be placed at the end.
To force the text to the right, you can add a another column definition to your grid:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
Place and emtpy object into the first cell, the one to the left:
number from the top (0)
number from the left (0)
and your label into the second cell, the one to the right:
number from the top (0)
number from the left (1)
The text area will adjust to the text length and will always be to the right.
I hope this information helps!
You can read more about grid in the documentation:
https://learn.microsoft.com/en-us/xamarin/android/user-interface/layouts/grid-layout

How to change Label Text color of masterPageitem after selection

I'm new to Xamarin framework and want to create an app using Master-Detail Page
I did simple Master-Detail Navigation page demo from xamarin websit
master-detail-page xamarin webise
only difference is I used ViewCell inside DataTemplate.In ViewCell I have Label
instead of Image.
after clicking on MasterPageItems navigation is working fine but now I want to change the label Text color also .
<ListView x:Name="listView" VerticalOptions="FillAndExpand" SeparatorVisibility="None" RowHeight="50" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Title}" TextColor="#1ca7ec" FontSize="18"></Label>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = e.SelectedItem as MasterPageItem;
if (item != null)
{
Detail = new NavigationPage((Page)Activator.CreateInstance(typeof(ContactsPage)));
masterPage.ListView.SelectedItem = null;
IsPresented = false;
}
}
I think you can do in this way:
1- in your model you should have a "TextColor" property and a "Selected" property
public bool Selected { get; set; }
// I think you should not return "Color" type (for strong MVVM) but, for example, a value that you can convert in XAML with a IValueConverter...
public Color TextColor
{
get
{
if (Selected)
return Color.Black;
else
return Color.Green;
}
}
2- In your XAML you should have something like
<ListView SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding List}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}" TextColor="{Binding TextColor}" FontSize="18"></Label>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
3- and in your ViewModel something like
MyModel _selectedItem { get; set; }
public ObservableCollection<MyModel> List { get; set; } = new ObservableCollection<MyModel>();
public MyModel SelectedItem
{
get { return _selectedItem; }
set
{
if (_selectedItem != null)
_selectedItem.Selected = false;
_selectedItem = value;
if (_selectedItem != null)
_selectedItem.Selected = true;
}
}
When your item in the list is selected , SelectedItem property change and Selected property in your model became True or False, changing the TextColor property (I use PropertyChanged.Fody for INPC).
Hope this help
You can find the repo on GitHub
Instead of use a TextColor Property in your Model, I think you can also use only Selected property and an IValueConverter that convert Selected property to a color

Resources