I am trying to add a bindable property to an entry in Xamarin.Forms. This should allow me to set/unset the keyboard focus for the Entry by assigning a boolean to the HasFocus property. I am using ReactiveUI as a MVVM framework and the RaiseAndSetIfChanged method raises the INotifyPropertyChanged event implicitly (which works in many other places).
I am not able to hit any breakpoints in my FocusedEntry class and I am not seeing the keyboard coming up. What am I missing?
// XAML
<controls:FocusedEntry Text="My custom Entry"
HasFocus="{Binding EntryHasFocus, Mode=TwoWay}"/>
// View Model
private bool _entryHasFocus;
public bool EntryHasFocus
{
get => _entryHasFocus;
private set => this.RaiseAndSetIfChanged(ref _entryHasFocus, value);
}
// Custom View
public class FocusedEntry : Entry
{
public static readonly BindableProperty HasFocusProperty = BindableProperty.Create(
nameof(HasFocus), typeof(bool), typeof(FocusedEntry), false, BindingMode.TwoWay, propertyChanged: OnHasFocusedChanged);
public bool HasFocus
{
get => (bool)GetValue(HasFocusProperty);
set => SetValue(HasFocusProperty, value);
}
private static void OnHasFocusedChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is FocusedEntry entry)
{
bool hasFocus = (bool)newValue;
bool wasFocused = (bool)oldValue;
if (hasFocus == wasFocused) return;
if (hasFocus)
entry.Focus();
else
entry.Unfocus();
}
}
}
The code actually worked all along. For some reason, Visual Studio was not updating the App on my iPad and I was testing with an old version of my app.
Related
I created a custom ContentView with a Image and a Label.
I also created a property of ImageUrl and LabelText.
I want this ContentView an receive a Binding value in a listview
<MyCustomContentView ImageUrl="{Binding Image}" LabelText="{Binding Text}" />
but it says there is no bindable property.how to create it?
You can use this code and paste it below the constructor of the MyCustomContentView class in the code behind file.
public static readonly BindableProperty LabelTextProperty = BindableProperty.Create(nameof(LabelText), typeof(string), typeof(MyCustomContentView), default(string));
public static readonly BindableProperty ImageUrlProperty = BindableProperty.Create(nameof(ImageUrl), typeof(string), typeof(MyCustomContentView), default(string));
public string LabelText { get => (string)GetValue(LabelTextProperty); set => SetValue(LabelTextProperty, value); }
public string ImageUrl { get => (string)GetValue(ImageUrlProperty); set => SetValue(ImageUrlProperty, value); }
Let me know if you have further difficulties
I am trying to do a simple override and load some data when my page loads, I am using the following code in the code behind page.
namespace XYZ
{
public partial class MainPage : ContentPage
{
private Label results;
private Label groupResults;
public MainPage()
{
InitializeComponent();
results = new Label();
groupResults = new Label();
}
protected override void OnAppearing()
{
base.OnAppearing();
storeIdTxt.Text = Settings.StoreIdSetting;
}
}
}
If I uncomment the override things works just fine, the error I am getting seems to be a generic one attached here
my settings class is fairly simple as follows
using System;
using System.Collections.Generic;
using System.Text;
using Plugin.Settings;
using Plugin.Settings.Abstractions;
namespace NWMPosNG.Helpers
{
/// <summary>
/// This is the Settings static class that can be used in your Core solution or in any
/// of your client applications. All settings are laid out the same exact way with getters
/// and setters.
/// </summary>
public static class Settings
{
private static ISettings AppSettings
{
get
{
return CrossSettings.Current;
}
}
#region Setting Constants
private const string SettingsKey = "settings_key";
private static readonly string SettingsDefault = string.Empty;
private const string StoreId = null;
private static readonly string StoreIdDefault = "0";
#endregion
public static string GeneralSettings
{
get
{
return AppSettings.GetValueOrDefault(SettingsKey, SettingsDefault);
}
set
{
AppSettings.AddOrUpdateValue(SettingsKey, value);
}
}
public static string StoreIdSetting
{
get
{
return AppSettings.GetValueOrDefault(StoreId, StoreIdDefault);
}
set
{
AppSettings.AddOrUpdateValue(StoreId, value);
}
}
}
}
I narrowed down the issue to when I access the saved data using
storeIdTxt.Text = Settings.StoreIdSetting;
But I don't understand why that causes the crash.
You are using the Settings Plugin from James Montemagno. Which is pretty much a KeyValuePair that is stored on the local device across sessions.
In your case:
AppSettings.GetValueOrDefault(StoreId, StoreIdDefault);
Translates to:
AppSettings.GetValueOrDefault(null, "0");
Which crashes because 'null' can't be a key. That's why setting the key (StoreId) prevents the crash from happening.
This line was the culprit
private const string StoreId = null;
I don't really understand why but setting this to a non NULL value makes the crash go away
I have a picker control:
<Picker Title="Number of People"
ItemsSource="{Binding SomeList, Source={x:Static local:MyModelHandler.MyModel}}"
SelectedItem="{Binding SomeListSelectedIndex, Source={x:Static local:MyModelHandler.MyModel}}">
</Picker>
when trying to build i get "No property, bindable property, or event found for 'ItemsSource'" error.
Above that i have a label:
<Label Text ="{Binding SomeLabel, Source={x:Static local:MyModelHandler.MyModel}, Mode=OneWay}"></Label>
And that binding works perfectly
MyModelHandler is an static class that allowes only one Model
public static class MyModelHandler
{
private static MyModel myModel = new MyModel();
public static MyModel MyModel
{
get
{
return myModel;
}
}
}
And Model is simple:
public class MyModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int selectedNumber = 1;
private string someLabel = "";
public IList<int> SomeList
{
get
{
return Enumerable.Range(1, 10).ToList();
}
}
public int SomeListSelectedIndex
{
get
{
return SomeList.IndexOf(this.selectedNumberOfPeople);
}
set
{
this.selectedNumber = SomeList[value];
}
}
public double SomeLabel
{
get
{
return this.someLabel;
}
set
{
this.someLabel= value;
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
...
}
Edit: Using Xamarin 4.3
You might check your Xamarin.Forms version.
The ItemsSource property was introduced in Xamarin.Forms 2.3.4.184-pre1, see release notes here:
https://developer.xamarin.com/releases/xamarin-forms/xamarin-forms-2.3/2.3.4-stable/#2.3.4.184-pre1.
If you are using an older Xamarin.Forms version you will get the Xamarin.Forms XAML error "No property, bindable property, or event found for 'ItemsSource'".
That is a very strange way to set up the binding context for a view. The fact you have to specify the source for each element adds a lot of extra boilerplate code.
Try setting the bindingcontext to the model in the the view constructor
BindingContext = new MyModel ();
Then the XAML becomes
<Picker Title="Number of People"
ItemsSource="{Binding SomeList}"
SelectedItem="{Binding SomeListSelectedIndex}">
</Picker>
Or use a proper MVVM framework and save yourself a lot of grief. I can recommend FreshMvvm.
https://github.com/rid00z/FreshMvvm
I'm working with an editable Grid with Vaadin 7. When a row is in edit mode, it shows two buttons: save and cancel.
(Just in case, the image was taken from here Book of Vaadin)
With the:
grid.getEditorFieldGroup().addCommitHandler(new CommitHandler() {
private static final long serialVersionUID = 1L;
#SuppressWarnings("unchecked")
#Override
public void preCommit(CommitEvent commitEvent) throws CommitException{}
#Override
public void postCommit(CommitEvent commitEvent) throws CommitException{}
});
I can do something in the save action.
But, can I do something like that with the cancel action?
Thank you.
This is a serious deficiency of the component. According to the forum, they're working on it, but for the time being it seems that the most straightforward way is to extend the Grid component and override the doCancelEditor method. Here's a snippet:
public class MyGrid extends Grid {
protected Object newRow;
#Override
protected void doCancelEditor() {
super.doCancelEditor();
getContainerDataSource().removeItem(newRow);
setEditorEnabled(false);
}
public void setNewRow(Object newRow) {
this.newRow = newRow;
}
Note that you have to tell the MyGrid object when you create the row. Also, note that you're extending the server side, so you don't have to alter the client (widget code), but you do need to refer to the new component in your UI design.
Actually, saveEditor() should be also overridden, as doCancelEditor() seems to be invoked on save action, too. My code:
public class MyGrid extends Grid {
private boolean addingMode = false;
private JPAContainer<SomeEntity> container;
private Object recentlyAddedItemID;
public MyGrid(Indexed indexed) {
container = indexed;
}
#Override
protected void doCancelEditor() {
Object id = getEditedItemId();
super.doCancelEditor();
if (addingMode) {
getContainerDataSource().removeItem(id);
recentlyAddedItemID = null;
}
addingMode = false;
}
#Override
public void saveEditor() throws FieldGroup.CommitException {
if (addingMode) recentlyAddedItemID = getEditedItemId();
addingMode = false;
super.saveEditor();
}
public Object getRecentlyAddedItemID() {
return recentlyAddedItemID;
}
public void addNewElement(SomeEntity entity) {
addingMode = true;
editItem(container.addEntity(entity));
}
}
MyGrid grid = new MyGrid(JPAContainerFactory.make(SomeEntity.class, entityManager));
grid.addNewElement(new SomeEntity());
/*
if we want to know the new items's ID (actually the new primary key
in case of JPAContainer), we can check it by:
*/
Object id = grid.getRecentlyAddedItemID();
/*
returns null if editor was cancelled and finally nothing new was persisted
*/
I am using the standard pivot template in my WP7 app.
I have the MainViewModel class defined with a few extra properties:
public class MainViewModel : INotifyPropertyChanged
{
...
private MyClass selectedKey_m;
public MyClass SelectedKey
{
get
{
...
}
set
{
if (value != this.selectedKey_m)
{
this.selectedKey_m = value;
NotifyPropertyChanged("SelectedKey");
}
}
}
}
The App class has a view model instance:
private static MainViewModel viewModel = null;
public static MainViewModel ViewModel
{
get
{
// Delay creation of the view model until necessary
if (viewModel == null)
viewModel = new MainViewModel();
return viewModel;
}
}
My MainPage.xaml.cs sets the DataContext:
DataContext = App.ViewModel;
From here, I can set up two way bindings on ListBoxes and I know it works because if I put a breakpoint on the SelecetdKey property in my viewmodel I can see the setter get called.
My problem is that I have my own user control, with a bindable property, bound to the SelectedKey property of the view model, but the property in my user control never gets set when the viewmodel gets updated and I can't figure out why.
Here is my user control:
public partial class MyUserControl : UserControl
{
public static readonly DependencyProperty SelectedKeyProperty = DependencyProperty.Register(
"SelectedKey", typeof(MyClass), typeof(MyUserControl), new PropertyMetadata(null));
public MyClass SelectedKey
{
get { return (MyClass)this.GetValue(SelectedKeyProperty); }
set { this.SetValue(SelectedKeyProperty, value); }
}
}
And here is the xaml in my main page:
<local:MyUserControl x:Name="myUC" SelectedKey="{Binding Path=SelectedKey}">
I would expect that the setter for the SelectedKey property of my user control to get called when the SelectedKey property of the view model gets changed, but it doesn't.
I've also tried setting the datacontext of my user control in the xaml:
DataContext="{Binding Path=App.ViewModel}"
The debugger does not step into the setter, don't know why.
Try adding a callback invoked on property value changes :
public static readonly DependencyProperty SelectedKeyProperty = DependencyProperty.Register(
"SelectedKey", typeof(MyClass), typeof(MyUserControl), new PropertyMetadata(MyPropertyChanged));
private static void MyPropertyChanged( object sender, DependencyPropertyChangedEventArgs args)
{
}
Solved. I had to add the static method as ptauzen suggested, but also remove the DataContext binding statement from my xaml :
DataContext="{Binding Path=App.ViewModel}"
Because the MainPage sets the datacontext in the constructor, so because my user control is a child of the main page, it inherits the data context. All I needed was to ensure the binding of my user controls properties were set up:
SelectedKey="{Binding SelectedKey}"