Im having a problem with listview and im almost giving upp.
I have a CustomButton inside a ListView, OnPressUp it should trigger an event.
The problem is that when i touch on button its trigering an event of multiple other buttons somehow.
Here is my Code please tell if you figure out something strange.
XAML
<StackLayout Orientation="Vertical">
<Label Text="Video Properties" Style="{ StaticResource HeaderContainer}"></Label>
<controls:YListView x:Name="lstVideosProperties" OnSelected="LstVideosProperties_OnSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid VerticalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"></ColumnDefinition>
<ColumnDefinition Width="8*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
</Grid.RowDefinitions>
<Image Aspect="Fill" VerticalOptions="FillAndExpand" Source="{Binding DefaultThumbnailUrl}" Grid.Row="0" Grid.Column="0"></Image>
<Grid Grid.Row="0" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7*"></ColumnDefinition>
<ColumnDefinition Width="3*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="4*"></RowDefinition>
<RowDefinition Height="6*"></RowDefinition>
</Grid.RowDefinitions>
<StackLayout Style="{StaticResource FormFloatLeft}" Grid.Row="0" Grid.Column="0">
<Label Text="{Binding Title}" Style="{StaticResource Header}" />
</StackLayout>
<controls:CustomButton Grid.RowSpan="2"
CommandParameter="{Binding VideoId}"
IsEnabled="{Binding VideoId ,Converter={StaticResource Downloadable}}"
Grid.Row="0" Grid.Column="1"
x:Name="_btnDownload"
OnPressUp="_btnDownload_OnPressUp"
Image="download.png"
HorizontalOptions="EndAndExpand"
VerticalOptions="StartAndExpand"
Style="{StaticResource Icon}" />
<StackLayout VerticalOptions="Start" Style="{StaticResource FormFloatLeft}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
<Label Text="{Binding Views}" Style="{StaticResource UnderText}" />
</StackLayout>
</Grid>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</controls:YListView>
DATABIND ITEMS
lstVideosProperties.ItemsSource = _videos;
CUSTOMBUTTON
public class CustomButton : Button
{
public CustomButton()
{
ColorBeforeSelection = Color.Transparent;
}
public Color OnPressColor { get; set; } = ((Color)Application.Current.Resources["pressed"]);
private Color ColorBeforeSelection;
public TextAlignment? TextAlignment { get; set; }
public event EventHandler OnPressUp;
public event EventHandler OnPressDown;
public Action<double, double> SizeAllocated;
public bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
if (_isSelected)
{
if (this.BackgroundColor != OnPressColor)
ColorBeforeSelection = this.BackgroundColor;
this.BackgroundColor = OnPressColor;
}
else
this.BackgroundColor = ColorBeforeSelection;
}
}
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
SizeAllocated?.Invoke(width, height);
}
public void OnPressed()
{
OnPressDown?.Invoke(this, null);
}
public void OnReleased()
{
OnPressUp?.Invoke(this, null);
}
}
CustomButtonRenderer
public class CustomButtonRenderer : ButtonRenderer
{
Context _context;
public CustomButtonRenderer(Context context) : base(context)
{
_context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
var customRendererButton = e.NewElement as CustomButton;
var control = Control as Android.Widget.Button;
switch (customRendererButton.TextAlignment)
{
case Xamarin.Forms.TextAlignment.Center:
control.Gravity = GravityFlags.Center | GravityFlags.CenterVertical;
break;
case Xamarin.Forms.TextAlignment.Start:
control.Gravity = GravityFlags.Left | GravityFlags.CenterVertical;
break;
case Xamarin.Forms.TextAlignment.End:
control.Gravity = GravityFlags.End | GravityFlags.CenterVertical;
break;
}
if (!customRendererButton.IsEnabled)
{
control.SetBackgroundColor(new Android.Graphics.Color(
ContextCompat.GetColor(_context, Resource.Color.disabled_background)
));
}
bool selected = customRendererButton.IsSelected;
bool prevent = false;
Timer _timer = null;
control.Touch += (object sender, TouchEventArgs args) =>
{
if (!customRendererButton.IsEnabled)
{
control.SetBackgroundColor(new Android.Graphics.Color(
ContextCompat.GetColor(_context, Resource.Color.disabled_background)
));
return;
}
if (args.Event.Action == MotionEventActions.Up)
{
_timer.Stop();
if (!selected)
customRendererButton.IsSelected = false;
if (!prevent)
customRendererButton.OnReleased();
prevent = false; // reset
return;
}
else if (args.Event.Action == MotionEventActions.Down)
{
_timer?.Stop();
_timer = new Timer(200);
_timer.Elapsed += new ElapsedEventHandler((o, arg) =>
{
if (!selected)
customRendererButton.IsSelected = false;
prevent = true;
});
_timer.Start();
selected = customRendererButton.IsSelected;
if (!customRendererButton.IsSelected)
customRendererButton.IsSelected = true;
customRendererButton.OnPressed();
return;
}
else if (args.Event.Action == MotionEventActions.Move)
{
}
};
}
}
Bind button's command in this way :
Command="{Binding Path=BindingContext.CommandName,Source={x:Reference root}}" CommandParameter="{Binding .}"
Define page name as this "x:Name="root"" in your page's opening bracket.(name can be anything)
Related
I am displaying results and I added the ability to edit the displayed result. That works I get pop up with the text I want to edit. However I need to go up and down to display the edited text. I have tried to add IsRefreshong property but that has the same result. Do you have any suggestions? I need to display the edited text after I click on "ok " in my pop up not have to scroll down or up and then see the updated property
here is my xaml
<ListView BackgroundColor="{DynamicResource PageBackgroundColor}" x:Name="list"
HasUnevenRows="True" IsRefreshing="{Binding IsRefreshing}"
HorizontalOptions="CenterAndExpand"
VerticalOptions="FillAndExpand"
VerticalScrollBarVisibility="Never"
CachingStrategy="RecycleElement"
ItemsSource="{Binding Results, Mode=TwoWay}"
SeparatorVisibility="Default"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="{DynamicResource PageBackgroundColor}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="12*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="12*"/>
<ColumnDefinition Width="4*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="1" Padding="0,3,3,0" Text ="{Binding FieldDescriptor}" Style="{StaticResource SubLabelBlackStyle}" HorizontalOptions="Start" BackgroundColor="{DynamicResource PageBackgroundColor}" HorizontalTextAlignment="Start" />
<Label Grid.Column="3" Padding="0,3,3,0" Text="{Binding FieldValue}" Style="{StaticResource SubLabelBlackStyle}" HorizontalOptions="Start" BackgroundColor="{DynamicResource PageBackgroundColor}" HorizontalTextAlignment="Start" >
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.EditTextCommand, Source={x:Reference Name=list}}" CommandParameter="{Binding .}"/>
</Label.GestureRecognizers>
</Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
here is the back of my page
public DisplayResult(RemoteCallResult<IEnumerable<DocumentData>> data)
{
InitializeComponent();
BindingContext = new ResultPageViewModel(data);
}
ViewModel property isRefreshing
public bool IsRefreshing
{
get => _isRefreshing;
private set
{
_isRefreshing = value;
NotifyPropertyChanged("IsRefreshing");
}
}
here is the edit method
public async Task EditTextAsync(DocumentData param)
{
PromptResult pResult = await UserDialogs.Instance.PromptAsync(new PromptConfig
{
InputType = InputType.Default,
Text = param.FieldValue,
Title = param.FieldValue,
});
if(pResult != null)
{
_isRefreshing = true;
param.FieldValue = pResult.Text;
Thread.Sleep(5);
_isRefreshing = false;
}
}
MYmodel
public string FieldValue { get; set; }
public string FieldDescriptor { get; set; }
Text="{Binding FieldValue,Mode=TwoWay}"
Add a two-way binding mode and you have not posted the DocumentData Model, Raise this FieldValue property in the model as well. It should do it.
You do not need to use is IsRefreshing tag for changing the value in the MVVM.
Here is running gif.
Please change the viewModel like following format. Achieve the INotifyPropertyChanged interface for all of your properties.
using System.ComponentModel;
using System.Text;
namespace PanCakeView
{
public class MyModel: INotifyPropertyChanged
{
string fieldValue;
public string FieldValue
{
set
{
if (fieldValue != value)
{
fieldValue = value;
OnPropertyChanged("FieldValue");
}
}
get
{
return fieldValue;
}
}
string fieldDescriptor;
public string FieldDescriptor
{
set
{
if (fieldDescriptor != value)
{
fieldDescriptor = value;
OnPropertyChanged("FieldDescriptor");
}
}
get
{
return fieldDescriptor;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Here is my viewModel. I used ObservableCollection for testing.
public class ResultPageViewModel
{
public ObservableCollection<MyModel> Results { get; set; }
public ICommand EditTextCommand { protected set; get; }
public ResultPageViewModel(ObservableCollection<MyModel> myModels)
{
Results = new ObservableCollection<MyModel>();
foreach (var item in myModels)
{
Results.Add(item);
}
EditTextCommand = new Command<MyModel>(async (key) =>
{
PromptResult pResult = await UserDialogs.Instance.PromptAsync(new PromptConfig
{
InputType = InputType.Default,
Text = key.FieldValue,
Title = "change value",
});
if (pResult!=null)
{
key.FieldValue = pResult.Text;
}
});
}
}
I do not know which style you used. I just use style that I setted.
<ListView BackgroundColor="AliceBlue" x:Name="list"
HasUnevenRows="True"
HorizontalOptions="CenterAndExpand"
VerticalOptions="FillAndExpand"
VerticalScrollBarVisibility="Never"
CachingStrategy="RecycleElement"
ItemsSource="{Binding Results, Mode=TwoWay}"
SeparatorVisibility="Default"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="Gray">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="12*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="12*"/>
<ColumnDefinition Width="4*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="1" Padding="0,3,3,0" Text ="{Binding FieldDescriptor}" HorizontalOptions="Start" HorizontalTextAlignment="Start" />
<Label Grid.Column="3" Padding="0,3,3,0" Text="{Binding FieldValue}" HorizontalOptions="Start" HorizontalTextAlignment="Start" >
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.EditTextCommand, Source={x:Reference Name=list}}" CommandParameter="{Binding .}"/>
</Label.GestureRecognizers>
</Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Here is layout's background code.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
ObservableCollection<MyModel> data = new ObservableCollection<MyModel>();
data.Add(new MyModel() { FieldDescriptor= "this is a Descriptor", FieldValue="1" });
data.Add(new MyModel() { FieldDescriptor = "this is a Descriptor", FieldValue = "2" });
data.Add(new MyModel() { FieldDescriptor = "this is a Descriptor", FieldValue = "3" });
data.Add(new MyModel() { FieldDescriptor = "this is a Descriptor", FieldValue = "4" });
data.Add(new MyModel() { FieldDescriptor = "this is a Descriptor", FieldValue = "5" });
data.Add(new MyModel() { FieldDescriptor = "this is a Descriptor", FieldValue = "6" });
this.BindingContext = new ResultPageViewModel(data);
}
}
==============Update=====================
If you use PopUp page,Here is running gif.
Here is my popup page code.
<?xml version="1.0" encoding="utf-8" ?>
<pages:PopupPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
x:Class="PanCakeView.MyPopUpPage">
<Frame
VerticalOptions="Center"
HorizontalOptions="Center"
Padding="20, 20, 20, 20">
<StackLayout>
<Entry x:Name="entryCardName"
FontSize="Small"
Placeholder="{Binding FieldValue}"
Text="{Binding FieldValue}"
TextColor="Black"
ReturnType="Next">
</Entry>
<Button Text="Ok" Command="{Binding ConfirmPopUpCommand}" CommandParameter="{Binding }"/>
</StackLayout>
</Frame>
</pages:PopupPage>
PopUp page's background code.
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MyPopUpPage : Rg.Plugins.Popup.Pages.PopupPage
{
//public string FieldValue { get; set; }
private string _fieldValue;
public Command ConfirmPopUpCommand { get; }
public string FieldValue
{
set
{
_fieldValue = value;
}
get { return _fieldValue; }
}
public MyPopUpPage(MyModel myModel)
{
InitializeComponent();
_fieldValue = myModel.FieldValue;
ConfirmPopUpCommand = new Command(async (key) => {
myModel.FieldValue = FieldValue;
await PopupNavigation.Instance.PopAsync(true);
});
this.BindingContext = this;
}
}
}
Here is ResultPageViewModel.cs new code.
public class ResultPageViewModel
{
private ObservableCollection<MyModel> data;
private INavigation navigation;
public ObservableCollection<MyModel> Results { get; set; }
public ICommand EditTextCommand { protected set; get; }
public ResultPageViewModel(ObservableCollection<MyModel> myModels, INavigation navigation)
{
this.navigation = navigation;
Results = new ObservableCollection<MyModel>();
foreach (var item in myModels)
{
Results.Add(item);
}
EditTextCommand = new Command<MyModel>(async (key) =>
{
//PromptResult pResult = await UserDialogs.Instance.PromptAsync(new PromptConfig
//{
// InputType = InputType.Default,
// Text = key.FieldValue,
// Title = "change value",
//});
//if (pResult!=null)
//{
// key.FieldValue = pResult.Text;
//}
await navigation.PushPopupAsync(new MyPopUpPage(key));
});
}
}
}
You need add Navigation attribute in DisplayResult page. this.BindingContext = new ResultPageViewModel(data, Navigation);
The working looks correctly when the list starts but once the list is filled with more elements ie, when it needs to scroll for more elements the entry becomes disabled for all the remaining value in the UI , but when i check the model value for that particular entry its still true for Isenabled property
Here is my Xaml file:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyFirstApp.Demo">
<ContentPage.Content>
<StackLayout>
<StackLayout>
<Button Text="Add" Clicked="Button_Clicked"/>
</StackLayout>
<ListView x:Name="DimensionListView" HasUnevenRows="True" ItemsSource="{Binding List}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<Grid>
<Grid x:Name="DimensionsGrid" RowSpacing="0" ColumnSpacing="0" Grid.Row="0" Grid.Column="0" Margin="0,0,0,0" >
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width ="0.9*"/>
</Grid.ColumnDefinitions>
<Entry Text="{Binding Pieces }" IsEnabled="{Binding Isenabled}" Keyboard="Numeric" Placeholder="0" Grid.Column="0" Grid.Row="0" BackgroundColor="White" TextColor="Black" FontSize="Small" Margin="0,0,0,0" HorizontalTextAlignment="Center"/>
<Entry Text="{Binding Length}" IsEnabled="{Binding Isenabled}" Keyboard="Numeric" Placeholder="0" Grid.Column="1" Grid.Row="0" BackgroundColor="White" TextColor="Black" FontSize="Small" Margin="0,0,0,0" HorizontalTextAlignment="Center"/>
<Entry Text="{Binding Height }" IsEnabled="{Binding Isenabled}" Keyboard="Numeric" Placeholder="0" Grid.Column="2" Grid.Row="0" BackgroundColor="White" TextColor="Black" FontSize="Small" Margin="0,0,0,0" HorizontalTextAlignment="Center"/>
<Entry Text="{Binding Width}" IsEnabled="{Binding Isenabled}" Keyboard="Numeric" Placeholder="0" Grid.Column="3" Grid.Row="0" BackgroundColor="White" TextColor="Black" FontSize="Small" Margin="0,0,0,0" HorizontalTextAlignment="Center"/>
</Grid>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
My Code behind :
namespace MyFirstApp
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Demo : ContentPage
{
ShipmentViewModel ViewList = new ShipmentViewModel();
public Demo()
{
InitializeComponent();
ViewList.ShimpentDimsList = new ObservableCollection<VolumeCalculator>() { new VolumeCalculator() { Height = 0, Length = 0, Pieces = 0, Width = 0, Isenabled = true } };
DimensionListView.ItemsSource = ViewList.ShimpentDimsList;
}
private void Button_Clicked(object sender, EventArgs e)
{
ViewList.ShimpentDimsList.LastOrDefault().Isenabled = false;
ViewList.ShimpentDimsList.Add(new VolumeCalculator() { Pieces = 0, Height = 0, Width = 0, Length = 0, Isenabled = true });
ObservableCollection<VolumeCalculator> TempList = ViewList.ShimpentDimsList;
}
}
}
My Model:
namespace MyFirstApp
{
class VolumeCalculator : INotifyPropertyChanged
{
private int pieces;
public int Pieces {
get { return pieces; }
set
{
pieces = value;
OnPropertyChanged("Pieces");
}
}
private int width;
public int Width
{
get { return width; }
set
{
width = value;
OnPropertyChanged("Width");
}
}
private int height;
public int Height
{
get { return height; }
set
{
height = value;
OnPropertyChanged("Height");
}
}
private int length;
public int Length
{
get { return length; }
set
{
length = value;
OnPropertyChanged("Length");
}
}
private bool isenabled ;
public bool Isenabled {
get { return isenabled; }
set
{
isenabled = value;
OnPropertyChanged("Isenabled");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
My ViewMode:
namespace MyFirstApp
{
class ShipmentViewModel : INotifyPropertyChanged
{
private ObservableCollection<VolumeCalculator> shimpentDimsList;
public ObservableCollection<VolumeCalculator> ShimpentDimsList
{
get { return shimpentDimsList; }
set {
shimpentDimsList = value;
OnPropertyChanged("ShimpentDimsList");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Cause : It caused by the Caching Strategy of the ListView .To conserve memory, the native ListView equivalents for each platform have built-in features for reusing rows. Only the cells visible on screen are loaded in memory and the content is loaded into existing cells. This pattern prevents the application from instantiating thousands of objects, saving time and memory.
Solution : In your case , you need to set the Caching Strategy as RecycleElement
<ListView CachingStrategy="RecycleElement" x:Name="DimensionListView" HasUnevenRows="True" >
As the title indicates I have problems with navigation.
I have a page called EvaluationPage, It contains four ContentPage inside has a Grid.
On this level I have a button (FAB) and CollectionView.
The CollectionView has Itemsource with ObservableCollection
The FAB open ReferenciaLaboralPage in mode Modal. If the form that has this page is filled out and the save button is clicked, add an item to the observable collection of the itemsource. It is done by Singleton.
The collectionview updates the new item, the item has a tap gesture that executes a command to open the page that was previously opened in modal mode and this is where it is not working. The command does run but the NavigateAsync does not display the page.
XAML EvaluacionPage
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<CollectionView ItemsSource="{Binding ReferenciasPersonales}" EmptyView="No existen referencias" VerticalOptions="FillAndExpand" Grid.Row="0">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical"
ItemSpacing="0" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Grid>
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding SelectedCommand}" NumberOfTapsRequired="1" />
</Grid.GestureRecognizers>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<pancake:PancakeView Grid.Column="0">
<Label Text="{Binding Letter}" TextColor="White" />
</pancake:PancakeView>
<StackLayout Grid.Column="1" >
<Label Text="{Binding Nombre}" Style="{StaticResource RobotoBold}" FontSize="16" />
<Label Text="{Binding TipoReferencia}" Style="{StaticResource RobotoRegular}" />
<Label Text="{Binding Telefono}" Style="{StaticResource RobotoRegular}" />
<Label Text="{Binding TiempoConocerlo}" Style="{StaticResource RobotoRegular}" />
</StackLayout>
<Label Grid.Column="2" Text="{Binding FechaRegistro, StringFormat='{0:dd/MM/yyyy}'}" />
</Grid>
<BoxView HorizontalOptions="FillAndExpand" BackgroundColor="LightGray" HeightRequest="1" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<pancake:PancakeView Elevation="10" VerticalOptions="End" HorizontalOptions="End" Margin="0,0,20,22" HeightRequest="50" WidthRequest="50" CornerRadius="25" Grid.Row="0">
<pancake:PancakeView.GestureRecognizers>
<TapGestureRecognizer Command="{Binding OpenReferenciaCommand}" NumberOfTapsRequired="1" />
</pancake:PancakeView.GestureRecognizers>
<Label Text="" TextColor="White" Style="{StaticResource IconStyleSolid}" VerticalOptions="Center" HorizontalOptions="Center" />
</pancake:PancakeView>
</Grid>
CODE EvaluacionPageViewModel
public DelegateCommand OpenReferenciaCommand => _openReferenciaCommand ?? (_openReferenciaCommand = new DelegateCommand(ShowReferenciaPersonal));
async void ShowReferenciaPersonal()
{
await _navigationService.NavigateAsync("ReferenciaPersonalPage", useModalNavigation: true);
}
// Add item to datasource
public void AddReferenciaPersonal(ReferenciaPersonalItemViewModel item)
{
if (item.IdReferencia == 0)
{
ReferenciasPersonales.Add(item);
}
else
{
ReferenciasPersonales.Remove(ReferenciasPersonales.Where(w=>w.IdReferencia == item.IdReferencia).Single());
ReferenciasPersonales.Add(item);
ReferenciasPersonales = ReferenciasPersonales;
}
}
CODE ReferenciaPersonalPageViewModel
public class ReferenciaPersonalPageViewModel : ViewModelBase
{
private readonly INavigationService _navigationService;
private readonly IApiService _apiService;
private readonly IDialogService _dialogService;
private DelegateCommand _closeCommand;
private DelegateCommand _saveCommand;
private string _nombre;
private ReferenciaPersonalItemViewModel _item;
private bool _isRunning;
private bool _isEnable;
public ReferenciaPersonalPageViewModel(INavigationService navigationService, IApiService apiService, IDialogService dialogService) : base(navigationService)
{
_navigationService = navigationService;
_apiService = apiService;
_dialogService = dialogService;
_item = new ReferenciaPersonalItemViewModel(navigationService);
}
public string Nombre
{
get => _nombre;
set => SetProperty(ref _nombre, value);
}
public bool IsRunning
{
get => _isRunning;
set => SetProperty(ref _isRunning, value);
}
public bool IsEnable
{
get => _isEnable;
set => SetProperty(ref _isEnable, value);
}
#endregion
#region Commands
public DelegateCommand CloseCommand => _closeCommand ?? (_closeCommand = new DelegateCommand(ExecuteCloseCommand));
public DelegateCommand SaveCommand => _saveCommand ?? (_saveCommand = new DelegateCommand(ExecuteSaveCommand));
#endregion
#region Metodos
async void ExecuteCloseCommand()
{
await _navigationService.GoBackAsync();
}
private async void ExecuteSaveCommand()
{
IsRunning = true;
IsEnable = false;
_item.Direccion = Direccion;
_item.Nombre = Nombre;
_item.Telefono = Telefono;
_item.TiempoConocerlo = TiempoConocerlo;
_item.TipoReferencia = TipoReferencia;
_item.FechaRegistro = _item.IdReferencia > 0 ? _item.FechaRegistro : DateTime.Now.ToLocalTime();
EvaluacionPageViewModel.GetInstance().AddReferenciaPersonal(_item);
IsRunning = false;
IsEnable = true;
await _navigationService.GoBackAsync();
}
#endregion
public override void OnNavigatedTo(INavigationParameters parameters)
{
base.OnNavigatedTo(parameters);
if (parameters.ContainsKey("item"))
{
_item = parameters.GetValue<ReferenciaPersonalItemViewModel>("item");
Nombre = _item.Nombre;
Direccion = _item.Direccion;
Telefono = _item.Telefono;
TiempoConocerlo = _item.TiempoConocerlo;
TipoReferencia = _item.TipoReferencia;
}
}
}
CODE ReferenciaPersonalItemViewModel
public class ReferenciaPersonalItemViewModel : Referencia
{
private readonly INavigationService _navigationService;
private DelegateCommand _selectedCommand;
public ReferenciaPersonalItemViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
}
public DelegateCommand SelectedCommand => _selectedCommand ?? (_selectedCommand = new DelegateCommand(ShowItem));
private async void ShowItem()
{
await _navigationService.NavigateAsync("ReferenciaPersonalPage", useModalNavigation: true);
}
}
When I click on the (fab) button to open the modal the
NavigationUriPath before the NavigateAsync is:
/MainMasterDetailPage/NavigationPage/HomePage/ItineraryPage/EvaluationPage
When I click on the collectionview item to open modal the
NavigationUriPath before the NavigateAsync is:
/MainMasterDetailPage/NavigationPage/HomePage/ItinerarioPage/EvaluacionPage/ReferenciaPersonalPage?useModalNavigation=true
If I put the absolute path if it shows the page but shows it with a
navigation Bar
I am using xamarin forms listview.
I am using switch control on both listview and outside of listview:
When i click the event on outside of listview switch button or inside of listview switch button, it will affect bothin event class.
How to avoid these issue.
My code for xaml file is below:
<Label Margin="0,0,10,0" Text="Select All" TextColor="Black" FontSize="Medium" HorizontalOptions="End" VerticalOptions="Center"></Label>
<Switch Margin="0,0,10,0" x:Name="SelectToggled" HorizontalOptions="End" VerticalOptions="Center" Toggled="Switch_Toggled" ></Switch>
<ListView x:Name="LocationListView" HasUnevenRows="True" SeparatorVisibility="None" VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Margin="0,0,0,0" BackgroundColor="{Binding backgroundColor}" HeightRequest="47" RowSpacing="0" HorizontalOptions="FillAndExpand" Padding="20,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*"/>
<ColumnDefinition Width="20*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="{Binding CountryName}" HorizontalOptions="Start" VerticalOptions="Center" TextColor="Black" FontFamily="Roboto" FontSize="Medium"></Label>
<Switch Grid.Row="0" Grid.Column="1" HorizontalOptions="CenterAndExpand" Toggled="SwitchList_Toggled" VerticalOptions="CenterAndExpand" IsToggled="{Binding IsToggle,Mode=TwoWay}"></Switch>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My code for xaml.cs is:
public MarketLanding()
{
InitializeComponent();
ObservableCollection<Country> countrylist = new ObservableCollection<Country>();
countrylist.Add(new Country { CountryName = "India" });
countrylist.Add(new Country { CountryName = "America" });
countrylist.Add(new Country { CountryName = "England" });
for (int i = 0; i < countrylist.Count; i++)
{
if (i % 2 == 0)
{
countrylist[i].backgroundColor = Color.LightGray;
}
else
{
countrylist[i].backgroundColor = Color.White;
}
}
LocationListView.ItemsSource = countrylist;
}
private void Switch_Toggled(object sender, ToggledEventArgs e)
{
}
private void SwitchList_Toggled(object sender, ToggledEventArgs e)
{
}
Anyone please help me to sort out this issue.
You can foreach through CountryList, I do one sample that you can take a look:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="Test1.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Test1">
<StackLayout>
<Label
Margin="0,0,10,0"
FontSize="Medium"
HorizontalOptions="End"
Text="Select All"
TextColor="White"
VerticalOptions="Center" />
<Switch
x:Name="SelectToggled"
Margin="0,0,10,0"
BackgroundColor="BlueViolet"
HorizontalOptions="End"
Toggled="Switch_Toggled"
VerticalOptions="Center" />
<ListView
x:Name="LocationListView"
BackgroundColor="AliceBlue"
HasUnevenRows="True"
SeparatorVisibility="None"
VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid
Margin="0,0,0,0"
Padding="20,0,0,0"
BackgroundColor="{Binding backgroundColor}"
HeightRequest="47"
HorizontalOptions="FillAndExpand"
RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*" />
<ColumnDefinition Width="20*" />
</Grid.ColumnDefinitions>
<Label
Grid.Row="0"
Grid.Column="0"
FontFamily="Roboto"
FontSize="Medium"
HorizontalOptions="Start"
Text="{Binding CountryName}"
TextColor="Black"
VerticalOptions="Center" />
<Switch
x:Name="switch1"
Grid.Row="0"
Grid.Column="1"
HorizontalOptions="CenterAndExpand"
IsToggled="{Binding IsToggle, Mode=TwoWay}"
Toggled="SwitchList_Toggled"
VerticalOptions="CenterAndExpand" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
public ObservableCollection<Country> countrylist { get; set; }
public MainPage()
{
InitializeComponent();
countrylist = new ObservableCollection<Country>();
countrylist.Add(new Country { CountryName = "India",IsToggle=false });
countrylist.Add(new Country { CountryName = "America" ,IsToggle=true});
countrylist.Add(new Country { CountryName = "England" ,IsToggle=false});
for (int i = 0; i < countrylist.Count; i++)
{
if (i % 2 == 0)
{
countrylist[i].backgroundColor = Color.LightGray;
}
else
{
countrylist[i].backgroundColor = Color.White;
}
}
LocationListView.ItemsSource = countrylist;
}
private void Switch_Toggled(object sender, ToggledEventArgs e)
{
Console.WriteLine(" outside switch clicked");
if(SelectToggled.IsToggled)
{
for (Int32 i = 0; i < countrylist.Count; i++)
{
countrylist[i].IsToggle = true;
}
}
else
{
for (Int32 i = 0; i < countrylist.Count; i++)
{
countrylist[i].IsToggle = false;
}
}
}
private void SwitchList_Toggled(object sender, ToggledEventArgs e)
{
Console.WriteLine(" inside switch clicked");
}
public class Country:INotifyPropertyChanged
{
private string _CountryName;
public string CountryName
{
get { return _CountryName; }
set
{
_CountryName = value;
RaisePropertyChanged("CountryName");
}
}
private Color _backgroundColor;
public Color backgroundColor
{
get { return _backgroundColor; }
set
{
_backgroundColor = value;
RaisePropertyChanged("backgroundColor");
}
}
private bool _IsToggle;
public bool IsToggle
{
get { return _IsToggle; }
set
{
_IsToggle = value;
RaisePropertyChanged("IsToggle");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if(handler!=null)
{
handler(this,new PropertyChangedEventArgs(propertyName));
}
}
}
I am trying to add list to the items dynamically as a part of learning Data Binding. But the items are not getting added. The app is so simple to just add a string to the list.
The XAML Code is as follows
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<ListBox x:Name="TotalItems" Grid.Row="0" ItemsSource="{Binding Items_OC}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch" Width="440">
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Item : " VerticalAlignment="Top"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Top" Margin="1,0,0,0" FontSize="{StaticResource PhoneFontSizeLarge}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="NewItem" Grid.Column="0" TextWrapping="Wrap" Width="359"/>
<Button x:Name="Add" Grid.Column="1" Content="Add"/>
</Grid>
</Grid>`
The XAML.CS code is as follows
public ObservableCollection<Items> items_OC;
public ObservableCollection<Items> Items_OC
{
get
{
return items_OC;
}
set
{
if (items_OC != value)
{
MessageBox.Show("Item to added to collection");
items_OC = value;
NotifyPropertyChanged("Items_OC");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Items : INotifyPropertyChanged, INotifyPropertyChanging
{
string name;
public string Name
{
get
{
return name;
}
set
{
if (name != value)
{
NotifyPropertyChanging("Name");
name = value;
NotifyPropertyChanged("Name");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangingEventHandler PropertyChanging;
private void NotifyPropertyChanging(string propertyName)
{
if (PropertyChanging != null)
{
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
}
}
private void Add_Click(object sender, RoutedEventArgs e)
{
Items it = new Items { Name = NewItem.Text };
Items_OC.Add(it);
}
Thanks for the help..
What your code seems missing is setting DataContext. Generally, binding resolves path from DataContext property. When you bind ItemsSource property this way :
<ListBox x:Name="TotalItems" Grid.Row="0" ItemsSource="{Binding Items_OC}" ...>
application will search Items_OC property of ListBox's DataContext. Currently, it won't find the property because DataContext is null. You can set DataContext to xaml.cs file from C# code like this :
this.DataContext = this;
or from XAML :
<phone:PhoneApplicationPage
.......
.......
DataContext="{Binding RelativeSource={RelativeSource Self}}"
/>
Item.cs:
public class Item
{
public string Name { get; set; }
}
MainPage.xaml:
<Grid x:Name="ContentPanel">
<ListBox x:Name="TotalItems"
ItemsSource="{Binding Items}"
VerticalAlignment="Top">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="Item :" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Orientation="Vertical"
VerticalAlignment="Center"
Margin="0,10,0,0">
<TextBox x:Name="NewItemTextBox" />
<Button x:Name="AddNewItem"
Content="Add"
Click="AddNewItem_Click" />
</StackPanel>
</Grid>
MainPage.cs:
public ObservableCollection<Item> Items { get; set; }
public MainPage()
{
InitializeComponent();
Items = new ObservableCollection<Item> { new Item { Name = "Roman" } };
DataContext = this;
}
private void AddNewItem_Click(object sender, RoutedEventArgs e)
{
Items.Add(new Item { Name = NewItemTextBox.Text });
}
Make things simple, but not simpler!