Xamarin : An element with the key 'X' already exists in NameScope - xaml

I'm getting the following error when I try to push to a new page.
(I'm using Xamarin.Form 4.6.0.800)
{System.ArgumentException: An element with the key 'NewAccountLogo' already exists in NameScope
Parameter name: name
at Xamarin.Forms.Internals.NameScope.Xamarin.Forms.Internals.INameScope.RegisterName (System.String name, System.Object scopedElement) [0x0000e] in D:\a\1\s\Xamarin.Forms.Core\Internals\NameScope.cs:21
at amici.NewAccount.InitializeComponent () [0x00078] in C:\Users\X\source\repos\amici\amici\amici\obj\Debug\netstandard2.0\NewAccount.xaml.g.cs:46
at amici.NewAccount..ctor () [0x0000f] in C:\Users\X\source\repos\amici\amici\amici\NewAccount.xaml.cs:26
at amici.Logon+<OnCreateAccountClick>d__3.MoveNext () [0x0002a] in C:\Users\X\source\repos\amici\amici\amici\logon.xaml.cs:119 }
The error seems straight forward so I went back and renamed the element and then searched my project for the same name. (there is only one). Recompiled and tried it again, same message but with the new name? so I delete the element and tried recompiled and tried it again, interesting enough I get the same message but with the next element? So now I’m thinking maybe the error message is not quite right or is trying to tell me something else. I just can’t figure it out. Below is my xaml.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
NavigationPage.HasNavigationBar="True"
Title="New Account"
x:Class="amici.NewAccount">
<ContentPage.Content >
<ScrollView>
<Grid>
<StackLayout Margin="20" Padding="10" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1">
<Image x:Name="NewAccountLogo"/>
<Entry x:Name="NewEmail" Placeholder="Email"/>
<Entry x:Name="EmailConfirm" Placeholder="Confirm Email"/>
<Label Text="Password between 6 and 20 characters; must contain at least one lowercase letter, one uppercase letter, one numeric digit." Margin="0,0,0,5"></Label>
<Entry x:Name="NewPassword" IsPassword="true" Placeholder="Password"/>
<Entry x:Name="PasswordConfirm" IsPassword="true" Placeholder="Confirm Password"/>
<Label x:Name="bntCreatAccountButton" TextColor="Blue" Text="Create Account" HorizontalOptions="Center" Margin="0,25,0,0">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnCreateAccount" NumberOfTapsRequired="1" />
</Label.GestureRecognizers>
</Label>
</StackLayout>
<ActivityIndicator x:Name="WaitIcon" IsRunning="{Binding IsBusy}" VerticalOptions="Center" HorizontalOptions="Center" />
</Grid>
</ScrollView>
</ContentPage.Content>
</ContentPage>
code behind :
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class NewAccount : ContentPage
{
public NewAccount()
{
InitializeComponent ();
this.InitializeComponent();
this.BindingContext = this;
this.IsBusy = false;
var bkgrndGradient = new Gradient()
{
Rotation = 150,
Steps = new GradientStepCollection()
{
new GradientStep(Color.White, 0),
new GradientStep(Color.White, .5),
new GradientStep(Color.FromHex("#ccd9ff"), 1)
}
};
ContentPageGloss.SetBackgroundGradient(this, bkgrndGradient);
NewAccountLogo.Source = ImageSource.FromFile("logo.png");
}
async private void OnCreateAccount(object sender, EventArgs e)
{
string Message = string.Empty;
string title = string.Empty;
bool results = false;
IsBusy = true;
try
{
if (ComparisonBehavior.CompareValues(NewEmail.Text, NewPassword.Text, EmailConfirm.Text,PasswordConfirm.Text, ref Message, ref title))
{
await Task.Delay(1000);
results = RestController.CreateAccount(NewEmail.Text, NewPassword.Text);
IsBusy = false;
if (results)
{
await DisplayAlert("New Account Created.", "Thank You! Please check your email (junk mail) to activate your subscription.", "OK");
await Application.Current.MainPage.Navigation.PopAsync();
}else
{
if (Application.Current.Properties["resp"].ToString() == "Account exist")
{
await DisplayAlert("Account Exist", "Sorry this email already exist!", "OK");
}
}
}else
{
await DisplayAlert(title, Message, "OK");
}
}catch (Exception ex)
{
await DisplayAlert("internal Error", ex.Message, "OK");
} finally{
IsBusy = false;
}
}
}
any help would be appreciated.
Mike

In my Code behind I had InitializeComponent (); declared twice.

This type of issue generally happens when the system tries to Initialize the same components with the same name. Please check InitializeComponent(); maybe, it has declared twice.

In my case I was trying to bind a component to its' code behind class instead of its' view model. I was doing:
<Picker
BindingContext={x:Reference x:Name=ThisPage}
/>
The problem was that x:Name=ThisPage was actually trying to set a new name for X Namespace instead of referencing one, when I changed it to Name=ThisPage it worked fine.

Related

Xamarin binding IsEnabled does not works

I have this strange problem, where the binding seems completely ignored.
my xaml
<Button IsEnabled="{Binding ButtonEnabled}" x:Name="ButtonOK" BackgroundColor="Green" TextColor="White" Text="OK"/>
my C#
private bool _buttonEnabled = false;
public bool ButtonEnabled
{
get
{
// breakpoint 1, which never hits with value = false
return _buttonEnabled;
}
set
{
// breakpoint 2, which hits
_buttonEnabled = value;
OnPropertyChanged(nameof(ButtonEnabled));
}
}
private void ChassisEntry_TextChanged(object sender, TextChangedEventArgs e)
{
ButtonEnabled = ChassisEntry.Text != "";
}
private void PageScan_Appearing(object sender, EventArgs e)
{
ChassisEntry.Text = "";
}
I expect that when this page opens that ButtonOK is disabled, but it is not.
When I set breakpoints then breakpoint 1 (in the getter) never hits, its like if the xaml IsEnabled="{Binding ButtonEnabled}" is ignored.
The breakpoint 2 does hits, with value = false
What am I missing here ?
I googled this problem and found many similar questions, but all solutions given do not help with my problem.
Button IsEnabled binding not working properly
How to disable a button until all entries are filled?
Disable/Enable save button based on the mandatory field being null or empty using Behaviors
and many more
I am guessing you are using the xaml.cs page for holding your Bindings and hence if you are doing that there are two ways to do this
Set the BindingContext to the current class in the constructor before or right after InitializeComponent
BindingContext= this;
Or In your XAML
<ContentPage
....
x:Name="currentPage">
And in your button
<Button IsEnabled="{Binding ButtonEnabled, Source={x:Reference currentPage}}"
I would go with this: Set my Button in my XAML disabled.
<Button IsEnabled="False" x:Name="ButtonOK" BackgroundColor="Green" TextColor="White" Text="OK"/>
Then on my Entry control i would add the property TextChanged.
<Entry x:Name="ChassisEntry"
PlaceholderColor="DarkGray"
TextChanged="ChassisEntryChanged">
On xaml.cs file:
private void ChassisEntryChanged(object sender, TextChangedEventArgs e)
{
if (e.NewTextValue.Text != "")
{
ButtonOK.IsEnabled = true;
}
else
{
ButtonOK.IsEnabled = false;
}
}

How to display a label with click on listview

I want to show a label when i click on my item in my listview.
The real problem i don't know how to link between my viewmodel and my views
I want modify my label in viewmodel but I don't know if its possible currently.
My xaml :
<StackLayout>
<Label x:Name="labelperso"
Text="{Binding newProduct}"
IsVisible="{Binding Addproduct}"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
BackgroundColor="#000000"
FontSize="20"
Opacity="0"/>
<ListView ItemsSource="{Binding Products}" CachingStrategy="RecycleElement" RowHeight="50" >
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding CodeReferenceLibelle}" TextColor="Black"/>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<b:EventToCommandBehavior EventName="ItemSelected" Command="{Binding
SelectCommand}" Converter="{StaticResource SelectedItemConverter}"/>
</ListView.Behaviors>
my viewmodel :
#region labelperso property
private string _newProduct;
public string newProduct
{
get { return _newProduct; }
set { SetProperty(ref _newProduct, value); }
}
#endregion
#region Addproduct property
private bool _Addproduct;
public bool Addproduct
{
get { return _Addproduct; }
set { SetProperty(ref _Addproduct, value); }
}
#endregion
when I click on my item :
async Task Select()
{
newProduct = "Produit ajouté !";
basketManager.AddProductSkuAsync(sku);
newProduct = "";
await Task.Run(() => ShowText());
}
//I have tried this but I can't use my label in my view
async Task ShowText()
{
await labelperso.FadeTo(1);
await Task.Delay(1000);
await labelperso.FadeTo(0);
}
Why are you want to take the label "labelperso" in VM ? you can use it in xaml.cs instead.
You just need to add the event ItemSelected like this:
<ListView ItemsSource="{Binding Products}" ItemSelected="OnSelection">
In xaml.cs
void OnSelection(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
{
return;
}
//suppose the binding Object is Product
Product product = (Product)e.SelectedItem;
//labelperso.Text = "name = " + product.Name;
labelperso.FadeTo(1);
Task.Delay(1000);
labelperso.FadeTo(0);
}
Normally, VM are unrelated to Xaml, and we should not get labels from VM.
And we don't recommend it.But if you must, you can pass the Label in from the xaml.cs file like this:
You can define a variable in yourpage.xaml.cs:
public Label pageLabel;
and initial like this:
pageLabel = labelperso;
BindingContext = new YourViewmodel(this);
And in YourViewmodel.cs:
public Label ss;
public YourViewmodel(ContentPage parentPage)
{// here HomePage is your contentPage name of the page`
ss = ((HomePage)parentPage).pageLabel;//after this you can use it
}
You need to add a SelectedProduct property to your VM.
private string _SelectedProduct;
public string SelectedProduct
{
get { return _SelectedProduct; }
set { SetProperty(ref _SelectedProduct, value); }
}
You can then bind your ListView's SelectedItem to it
<ListView ItemsSource="{Binding Products}"
SelectedItem="{Binding SelectedProduct}"
CachingStrategy="RecycleElement"
RowHeight="50" >
You can then control the visibility of your label by binding to SelectedProduct via a "nullToVisibility" converter, or by using triggers etc.
You should try to use MVVM pattern rather than hacking with code behind.
Using MVVM you can add a Visible property to your viewmodel and bind the IsVisible property of the label to it.
Code will be much easy to read and maintain.

Xamarin form app: Keyboard type telephone allow to input negative values in Android but not in IOS

I have made an application in Xamarin From. Design the UI in xaml. My issue is when i define the Keyboard telephone in entry field it allow to input negative value in android app but in IOS it not allowed.
<StackLayout Spacing="20" Padding="0" Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Entry Text="{Binding Item.TextProvider2017}" HorizontalTextAlignment="End" FontSize="Small" WidthRequest="140" MinimumWidthRequest="60" Placeholder="For 2017" Keyboard="Telephone" Completed="NoOfProvider_Completed" Unfocused="NoOfProvider_Unfocused"/>
<Entry Text="{Binding Item.TextProvider2018}" HorizontalTextAlignment="End" FontSize="Small" WidthRequest="140" MinimumWidthRequest="60" Placeholder="For 2018" Keyboard="Telephone"/>
<Entry Text="{Binding Item.TextProvider2019}" HorizontalTextAlignment="End" FontSize="Small" WidthRequest="140" MinimumWidthRequest="60" Placeholder="For 2019" Keyboard="Telephone"/>
<Entry Text="{Binding Item.TextProvider2020}" HorizontalTextAlignment="End" FontSize="Small" WidthRequest="140" MinimumWidthRequest="60" Placeholder="For 2020" Keyboard="Telephone"/>
</StackLayout>
Keypad in Android:
Keypad in IOS:
In Android keypad have negative sign but IOS don't have. IS there any way to make both same.
This is the old answer, see below for an updated version
You're going to want to create a custom renderer for the Entry control which has the default behavior for UWP and Android, while adding a custom InputAccessoryView to your iOS UITextField.
Here's what your custom renderer for iOS might look like:
class MinusButtonEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control == null) return;
UIBarButtonItem button = new UIBarButtonItem("-", UIBarButtonItemStyle.Plain, (sender, args) =>
{
var position = Control.SelectedTextRange.Start;
var idx = (int) Control.GetOffsetFromPosition(Control.BeginningOfDocument, position);
Element.Text.Insert(idx, "-");
});
UIToolbar toolbar = new UIToolbar()
{
Items = new [] { button }
};
Control.InputAccessoryView = toolbar;
}
}
This code basically creates a button, adds that to a toolbar, and then assigns that toolbar to the underlying UITextField. You will of course want to customize the toolbar and toolbar button to suit your needs.
EDIT:
There's a better way to do this using Effects in Xamarin Forms.
This class goes in the iOS project and is the main effect:
using MyApp;
using UIKit;
using Xamarin.Forms;
[assembly:ResolutionGroupName("Xamarin")]
[assembly:ExportEffect(typeof(MinusButtonEntryEffect), "MinusButtonEntryEffect")]
namespace MyApp
{
public class MinusButtonEntryEffect : PlatformEffect<UIView, UITextField>
{
protected override void OnAttached()
{
if (Control == null) return;
var element = Element as Entry;
if (element == null) return;
UIBarButtonItem button = new UIBarButtonItem("-", UIBarButtonItemStyle.Plain, (sender, args) =>
{
var position = Control.SelectedTextRange.Start;
var idx = (int)Control.GetOffsetFromPosition(Control.BeginningOfDocument, position);
element.Text = element.Text.Insert(idx, "-");
});
UIToolbar toolbar = new UIToolbar()
{
Items = new[] { button }
};
Control.InputAccessoryView = toolbar;
}
protected override void OnDetached()
{
Control.InputAccessoryView = null;
}
}
}
This code goes in the PCL and allows us to access the effect from XAML:
public class MinusButtonEntryEffect : RoutingEffect
{
public MinusButtonEntryEffect () : base ("Xamarin.MinusButtonEntryEffect") { }
}
So your XAML would look something like this:
<Entry Text="{Binding Item.TextProvider2017}" HorizontalTextAlignment="End" FontSize="Small" WidthRequest="140" MinimumWidthRequest="60" Placeholder="For 2017" Keyboard="Telephone">
<Entry.Effects>
<local:MinusButtonEntryEffect />
</Entry.Effects>
</Entry>
Make sure that local is whatever namespace your effect is in, for example:
xmlns:local="clr-namespace:MyApp"

`<Run />` doesn't databind in designtime

I have a view model that inherits from ReactiveObject from reactiveui.net, something like
public sealed class TestViewModel : ReactiveObject
{
public sealed class NestedViewModel
{
private string _property;
public string VMProperty
{
get { return _property; }
set { this.RaiseAndSetIfChanged(ref _property, value); }
}
private string _suffix;
public string Suffic
{
get { return _suffix; }
set { this.RaiseAndSetIfChanged(ref _suffix, value); }
}
}
private NestedViewModel _nested = new NestedViewModel();
public Nested
{
get { return _nested; }¨
set { this.RaiseAndSetIfChanged(ref _nested, value); }
}
#if DEBUG
public TestViewModel() {
Nested.VMProperty = "Test string";
Nested.Suffix = "with suffix";
}
#endif
}
I can get the following to display both design-time and run-time:
<Page.DataContext>
<local:TestViewModel />
</Page.DataContext>
<TextBlock Text="{Binding Nested.VMProperty}" />
<TextBlock Text="{Binding Nested.Suffix}" />
but when I try to do this instead, no text is displayed design-time:
<Page.DataContext><!-- ... -->
<TextBlock>
<Run Text="{Binding Nested.VMProperty}" />
<Run Text="{Binding Nested.Suffix}" />
</TextBlock>
Run-time it still works, but I don't want to have to deploy to the device emulator every time I want to check some pixel pushing...
How do I get these properties do display inside a <Run /> tag during design time?
Paul Betts, the creator of the ReactiveUI framework, advocates hard-coding sample data into the Page's XAML:
<TextBlock>
<Run Text="Test String" x:Name="VMproperty" />
<Run Text="with suffix" x:Name="Suffix" />
</TextBlock>
You can then do the binding in the Page's code behind:
this.OneWayBind(ViewModel, vm => vm.VMproperty, v => v.VMproperty.Text);
this.OneWayBind(ViewModel, vm => vm.Suffix, v => v.Suffix.Text);
These ReactiveUI style bindings overwrite the sample data that was hard coded in the XAML. So you get sample data at design-time and data binding at runtime.
Source: https://groups.google.com/d/msg/reactivexaml/GrVHWm8tUuM/4EAxOsxc_LQJ
What about using FallbackValue in your binding? I use it frequently to check how bound content would look like and didn't have any problem.

Toggling BottomAppBar visibility not working?

I have a list of items - when one is selected, I'd like to slide the appbar up. This is what I have so far:
<AppBar IsOpen="{Binding BookIsSelected}">
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<AppBarButton Icon="Remove" Label="Remove Book" Command="{Binding RemoveBook}" Visibility="{Binding BookIsSelected, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityConverter}}" />
</StackPanel>
</Grid>
</AppBar>
In the gridview of books, I have this:
SelectedItem ="{Binding SelectedBook, Mode = TwoWay}" />
BookIsSelected:
private bool _bookSelected;
public bool BookIsSelected {
get {
return _bookSelected;
}
set {
SetProperty(ref _bookSelected, value);
}
}
I can see the get/set hit when I select a book, but the appbar never flies out. What am I doing wrong?
I can't see any obvious problems with the code that you've shown so far. However, you haven't shown the code for the SelectedBook property or SetProperty method, so perhaps your problem lies there? Your SelectedBook property should look something like this, setting BookIsSelected to true:
private YourDataType _selectedBook;
public YourDataType SelectedBook{
get {
return _selectedBook;
}
set {
SetProperty(ref _selectedBook, value);
BookIsSelected = true;
}
}
However, unless you set the BookIsSelected property back to false at some stage, this will only work once. Your SetProperty method should notify the INotifyPropertyChanged interface of property changes, as #Amer mentioned in the comments. It should look something like this example from the linked page:
private void SetProperty([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}