Xamarin Forms Prism Problem with navigation within a listview - xamarin.forms

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

Related

Xamarin Forms Bindings not showing on Page

I am facing a strange problem and i don't know why this happens. I have created an AccountPage showing the Username, Name and a Description which i bound from the viewmodel. The App checks whether a token exists and pushes a LoginPage if there is no token.
If i now push the create Account Page from the Loginpage and create an account i get popped back to the Account page. Although the OnAppearing Method on the AccountPage gets called and the Bindings have the correct values in the VM there is nothing shown in the view. When i close the app and restart it, however, i can see the values of the Bindings on the View. How does this happen and how can i fix this?
the AccoountPage:
ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewmodel="clr-namespace:DoggoApp.ViewModels"
x:DataType="viewmodel:AccountPageViewModel"
BindingContext="AccountPageViewModel"
Title="{Binding Username}"
BackgroundColor="#FBFDFB"
x:Class="DoggoApp.Views.AccountPage">
<ContentPage.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.27*"/>
<RowDefinition Height="0.1*"/>
<RowDefinition Height="0.3*"/>
<RowDefinition Height="0.7*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackLayout Orientation="Horizontal" Grid.Row="0">
<Frame CornerRadius="100" Padding="0" Margin="25" IsClippedToBounds="True">
<Image Source="default_user.jpg" Aspect="AspectFill" Scale="0.44" Margin="-60"/>
</Frame>
<StackLayout Margin="10,40">
<Label Text=""/>
<Label Text="Beiträge"
Style="{StaticResource AccountPage}"/>
</StackLayout>
<StackLayout Margin="10,40">
<Label Text=""/>
<Label Text="Follower"
Style="{StaticResource AccountPage}"/>
</StackLayout>
<StackLayout Margin="10,40">
<Label Text=""/>
<Label Text="Following"
Style="{StaticResource AccountPage}"/>
</StackLayout>
</StackLayout>
<StackLayout Grid.Row="1" Margin="15,-20">
<Label Text="{Binding Name}" FontAttributes="Bold" Style="{StaticResource AccountPage}"/>
<Label Text="{Binding Description}" Style="{StaticResource AccountPage}"/>
<Frame Padding="0,15">
<Button Text="Edit Profile" Margin="-20" Clicked="EditAccount_Clicked"/>
</Frame>
</StackLayout>
code behind:
namespace DoggoApp.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AccountPage : ContentPage
{
private static AccountPageViewModel accountPageViewmodel;
public AccountPage()
{
InitializeComponent();
BindingContext = accountPageViewmodel = new AccountPageViewModel();
}
protected override async void OnAppearing()
{
accountPageViewmodel.NotRefreshTokenAction = (async (obj) =>
{
await DisplayAlert("DoggoApp", "Please log in again", "Ok");
});
base.OnAppearing();
bool LoggedIn = await accountPageViewmodel.Login();
if (!LoggedIn)
{
await Navigation.PushAsync(new LoginPage());
return;
}
}
the viewmodel:
public partial class AccountPageViewModel : ObservableObject, INotifyPropertyChanged
{
// == constants ==
private static readonly IAccountService accountService = DependencyService.Get<IAccountService>();
private static readonly ISaveService saveService = DependencyService.Get<ISaveService>();
// == observable Properties ==
private string username;
[ObservableProperty]
private string name;
[ObservableProperty]
private string description;
public string Username
{
get { return username; }
set
{
username = value;
OnPropertyChanged(nameof(Username));
}
}
public Action<bool> NotRefreshTokenAction { get; set; }
// == Relay Commands ==
[RelayCommand]
public async Task<bool> Login()
{
try
{
bool refreshed = await accountService.RefreshToken();
if(refreshed)
{
AccountDto dto = await accountService.GetDisplayAccount();
Username = dto.username;
Name = dto.name;
Description = dto.description;
return true;
}
throw new Exception("refreshed was false");
}
catch(Exception ex)
{
string message = ex.Message;
Console.WriteLine(message);
return false;
}
}
Create Account VM:
namespace DoggoApp.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CreateAccountPage : ContentPage
{
private static CreateAccountViewModel createAccountViewModel;
public CreateAccountPage()
{
InitializeComponent();
BindingContext = createAccountViewModel = new CreateAccountViewModel();
createAccountViewModel.AccountCreatedAction = (async (obj) =>
{
await DisplayAlert("Doggoapp", "Registration Successfull", "Ok");
await Navigation.PopToRootAsync();
});
}
}
}

can I refresh after edit of text

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);

Popup RG plugins after edit no update for property

I am displaying my properties in list. I used to use Acr.UserDialogs to display popup however I have decided to switch to RG for better UI.
Now when I clock on one field and edit it when I go back to the original page the value stay the same as it was before update. I have tried to add RefreshPull but that doesn't help
Back of my page
public DisplayResult(RemoteCallResult<IEnumerable<DocumentData>> data)
{
InitializeComponent();
BindingContext = _resultPageViewModel = new ResultPageViewModel(data);
}
my Xaml
<ListView BackgroundColor="{DynamicResource PageBackgroundColor}" x:Name="list" IsPullToRefreshEnabled="{Binding Update}"
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, Mode=TwoWay}" 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>
VIEWMODEL
public string FieldValue
{
get => _fieldValue;
set => SetValue(ref _fieldValue, value);
}
public ResultPageViewModel()
{
}
public ResultPageViewModel(RemoteCallResult<IEnumerable<DocumentData>> data)
{
EditTextCommand = new Command<DocumentData>(async (key) => await EditTextAsync(key));
Update = new Command<string>(async (key) => await UpdateValue(key));
LoadText(data); }
public async Task EditTextAsync(DocumentData param)
{
await Navigation.PushPopupAsync(new EditPopUp(param));
}
public async Task UpdateValue(string value)
{
_fieldValue = value;
}
ViewModel POPUP
private readonly ResultPageViewModel _resultPageViewModel;
private string _fieldValue;
public Command ConfirmPopUpCommand { get; }
public string FieldValue
{
set
{
_fieldValue = value;
NotifyPropertyChanged(nameof(FieldValue));
}
get { return _fieldValue; }
}
public EditPopUpViewModel(DocumentData param)
{
_resultPageViewModel = new ResultPageViewModel();
_fieldValue = param.FieldValue;
ConfirmPopUpCommand = new Command(async () => await ExecuteConfirmPopUpCommand());
}
private async Task ExecuteConfirmPopUpCommand()
{
await _resultPageViewModel.UpdateValue(_fieldValue);
await PopupNavigation.Instance.PopAsync(true);
}
POP UP
<Entry x:Name="entryCardName"
FontSize="Small"
Placeholder="{Binding FieldValue}"
Text="{Binding FieldValue}"
TextColor="Black"
ReturnType="Next">
</Entry>
When you show the pop up, I think you should also pass the ViewModel to the popupPage:
public async Task EditTextAsync(DocumentData param)
{
await Navigation.PushPopupAsync(new EditPopUp(param), this);
}
Then in the POPUP, you does not need to create a new one:
public MainPage(DocumentData param, ResultPageViewModel model)
{
_fieldValue = param.FieldValue;
Command ConfirmPopUpCommand = new Command(async () => await ExecuteConfirmPopUpCommand(model));
}
private async Task ExecuteConfirmPopUpCommand(ResultPageViewModel model)
{
await model.UpdateValue(_fieldValue);
await PopupNavigation.Instance.PopAsync(true);
}
this is updating the private internal field, bypassing the setter and NotifyPropertyChanged
public async Task UpdateValue(string value)
{
_fieldValue = value;
}
you want to update the public property that will fire the setter and NotifyPropertyChanged
public async Task UpdateValue(string value)
{
FieldValue = value;
}

Xamarin.Forms Strange behavior of ListView

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)

Adding items to list using data binding in windows phone 8

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!

Resources