Xamarin.Forms - Picker selected Item binding not responding - c#

I am making simple mvvm binding with picker field in xamarin.forms. I am following this guide xamarin guide setting a picker's bindings
So I made a model:
public class Operation
{
public int Number { get; set; }
public string Name { get; set; }
}
An ViewModel:
private List<Operation> _operations;
public List<Operation> Operations
{
get { return _operations; }
set
{
_operations = value;
OnPropertyChanged();
}
}
and View:
<Picker
ItemsSource="{Binding Operations}"
ItemDisplayBinding="{Binding Number}"
SelectedItem = "{Binding SelectedOperation}"/>
<Entry x:Name="HelpEntry"
Text="{Binding SelectedOperation.Name}" />
In the Pickers list items are displayed correctly, but when I Select an item number, then binding inside a Entry is not displayed.
Ouestion is, what am I doing wrong?
By the way.. I am doing this because I need to get an selected Operation's Name as variable in my code-behind section, by using HelpEntry.Text. It's not a smartest way and do u have better idea to do that?
Any help would be much appreciate.

Your ViewModel should also contain the SelectedOperation property that should also call the OnPropertyChanged method in its setter.
Also you should consider using ObservableCollection instead of List in you view models.

Be sure that your ViewModel implements the INotifyPropertyChanged interface. The way to do this easily is to create a BaseViewModel that implements the interface and then inherit all of your concrete view model classes from this base class.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MainPageVM : ViewModelBase
{...}

Related

Return singleton value in MVVM for binding

I am trying to figure out if it is possible to use a value from a singleton as my binding. I want to do something like this?
public class MySingleton : INotifyPropertyChanged
{
//...inotifypropertychanged and singleton implementation
private bool _isChecked;
public bool IsChecked
{
get
{
return _isChecked;
}
set
{
_isChecked= value;
OnPropertyChanged("IsChecked");
}
}
//...other implementation
}
public class MyViewModel : INotifyPropertyChanged
{
//...inotifypropertychanged and other implementation
public bool IsAllChecked { get { return MySingleton.GetInstance().IsChecked; } }
}
Some Xaml:
<ToggleButton IsChecked = "{Binding IsAllChecked}"/>
I have tried this and the bindings don't seem to update. I have tried this with ObservableCollection and it works great but other types aren't. I figure that it is something special with ObservableCollection.
MyViewModel doesn't raise PropertyChanged for IsAllChecked property, update in UI will not happen (ObservableCollection is totally different case - INotifyCollectionChanged).
why not declare Instance property instead of GetInstance() method and bind to MySingleton.Instance directly?
"{Binding Path=IsChecked, Source={x:Static myNameSpace:MySingleton.Instance}}"

C# Binding global static string to UWP Textblock

everybody.
Does anyone knows how to bind global static string to UWP Textblock, with propertychange update in control?
I have tried a lot of things, such as:
Text="{Binding Path={local:AppSettings.StorageFolder}, Mode=OneWay}"
Text="{x:Bind Path=(local:AppSettings.StorageFolder), RelativeSource={RelativeSource Self}, Mode=OneWay}"
And none works. Always some error comes up, like:
"Nested types are not supported and
Value does not fall within the expected range"
I have managed to bind it to non static value in my class:
Text="{x:Bind viewModel.MyValue, Mode=OneWay}"
Any solution to this?
Thanx.
You simply can't bind to a static property in UWP the same way as you can in WPF. There is no x:Static markup extension available.
You have some options:
If the DataContext of the element is an instance of the type in which the static property is defined, you could bind to a static property as usual:
<TextBlock Text="{Binding MyStaticProperty}" />
public sealed partial class BlankPage1 : Page
{
public BlankPage1()
{
this.InitializeComponent();
this.DataContext = this;
}
public static string MyStaticProperty { get { return "Static..."; } }
}
If the static property is defined in another class, your best option would be to wrap the static property in a non-static one:
public sealed partial class BlankPage1 : Page
{
public BlankPage1()
{
this.InitializeComponent();
this.DataContext = this;
}
public static string MyWrapperProperty { get { return MyStaticClass.MyStaticProperty; } }
}
public static class MyStaticClass
{
public static string MyStaticProperty { get { return "Static..."; } }
}
If you want property change notifications it makes no sense to bind to a static property at all because the source object of a property must implement the INotifyPropertyChanged interface for you to be able to refresh the target property dynamically by raising the PropertyChanged event.
You could still wrap the static property in a non-static one of a view model that implements the INotifyPropertyChanged interface:
public class ViewModel : INotifyPropertyChanged
{
public string MyNonStaticProperty
{
get { return MyStaticClass.MyStaticProperty; }
set { MyStaticClass.MyStaticProperty = value; NotifyPropertyChanged(); }
}
//...
}
public static class MyStaticClass
{
public static string MyStaticProperty { get; set; }
}
You will obviosuly need to call NotifyPropertyChanged("MyNonStaticProperty") from the view model class whenever you want to refresh the target property in the view.
Currently in UWP when using x:Bind the end property (I.e. at the end of the path) must be mutable / nonstatic. However you can reference static properties prior to that such as x:Bind local:MyClass.Singleton.NonstaticProperty.
The use of functions at the end of the x:Bind property path can also address this kind of challenge.

using of INotifyPropertyChanged

Can someone explain me why need to use implementation of INotifyPropertyChanged when using binding in wpf?
I can bind properties without implementation of this interface?
For example i have code
public class StudentData : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
string _firstName = null;
public string StudentFirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
OnPropertyChanged("StudentFirstName");
}
}
}
And binding in .xaml
<TextBox Text="{Binding Path=StudentFirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="1"
Grid.Column="2"
VerticalAlignment="Center" />
this code from .xaml.cs
StudentData _studentData = new StudentData { StudentFirstName = "John", StudentGradePointAverage = 3.5};
public MainWindow()
{
InitializeComponent();
this.DataContext = _studentData;
}
why we need to use INotifyPropertyChanged in this case?
It is not my code.
You need INotifyPropertyChanged if you want a wpf form to be automatically updated when a property changes through code. Also some controllers might want to know if edits have been made in order to enable/disable a save-button, for instance. You also might be displaying the same property on different views; in this case INotifyPropertyChanged helps to immediately update the other view when you edit a property.
If you think that your form behaves well without INotifyPropertyChanged, then you can drop it.
Note that binding works even without INotifyPropertyChanged. See: Why does the binding update without implementing INotifyPropertyChanged?
I would implement the properties like this. In some rare cases it can help to avoid endless circular updates. And it is more efficient by the way.
private string _firstName;
public string StudentFirstName
{
get { return _firstName; }
set
{
if (value != _firstName) {
_firstName = value;
OnPropertyChanged("StudentFirstName");
}
}
}
Starting with C#6.0 (VS 2015), you can implement OnPropertyChanged like this:
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
When you bind to a property of StudentData such as the StudentFirstName then the binding class tests to see if the StudentData instance provides the INotifyPropertyChanged interface. If so then it will hook into the PropertyChanged event. When the event fires and it fires because of the StudentFirstName property then it knows it needs to recover the source value again because it has changed. This is how the binding is able to monitor changes in the source and reflect them in the user interface.
If you do not provide the INotifyPropertyChanged interface then the binding has no idea when the source value changes. In which case the user interface will not update when the property is changed. You will only see the initial value that was defined when the binding was first used.
It does need to be implemented in order for binding to work but that doesn't mean you always have to do it yourself. There are other options like Castle Dynamic Proxy (which wraps your classes in a proxy and injects INPC into all virtual properties) and Fody (which adds it to the IL in a post-processing step). It's also possible to implement yourself while at the same time reducing code bloat, as demonstrated in my answer to this question.

MVVM INotifyPropertyChanged conflict with base class PropertyChange

I'm relatively new to MVVM and I'm trying to understand how INotifyPropertyChanged interface works and how to implement it in my models. The approach that I decided to take was to implement it in each of my Business Object classes. The problem with that approach is that when I bind my View to a property in a Base class the PropertyChanged event in that base class never gets initialized (is null) and therefore the View does not refresh the data for that element when my Model changes. I was able to reproduce the problem with the example below.
I have a Person Base class:
public class Person : INotifyPropertyChanged
{
#region INotifyProperty
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public String Name
{
get
{
return _name;
}
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
private String _name;
}
And I have an Employee class inheriting from my Person Base class:
public class Employee : Person,INotifyPropertyChanged
{
#region INotifyProperty
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public String EmployeeID
{
get
{
return _employeeId;
}
set
{
_employeeId = value;
RaisePropertyChanged("EmployeeID");
}
}
private String _employeeId;
}
Here my View Model:
public class ViewModel : ViewModelBase<ViewModel>
{
private Employee _employee;
public ViewModel()
{
ChangeModelCommand = new RelayCommand(param=>this.ChangeModel() , param=>this.CanChangeModel);
Employee = new Employee()
{
Name = "BOB",EmployeeID = "1234"
};
}
public ICommand ChangeModelCommand { get; set; }
public Employee Employee
{
get
{
return _employee;
}
set
{
this._employee = value;
NotifyPropertyChanged(m=>m.Employee);
}
}
public void ChangeModel()
{
MessageBox.Show("CHANGING MODEL");
this.Employee.Name = "MIKE";
this.Employee.EmployeeID = "5678";
}
public bool CanChangeModel
{
get{ return true;}
}
}
And finally my View:
<Window.Resources>
<MVVM_NotificationTest:ViewModel x:Key="Model"></MVVM_NotificationTest:ViewModel>
</Window.Resources>
<Grid DataContext="{StaticResource Model}">
<StackPanel>
<Label Content="Employee Name"/>
<TextBox Text="{Binding Path=Employee.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<Label Content="Employee ID"/>
<TextBox Text="{Binding Path=Employee.EmployeeID,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Change Model" Height="30" Width="100" Margin="5" Command="{Binding Path=ChangeModelCommand}"/>
</StackPanel>
</Grid>
In this example I initialize my Employee VM Property in the VM constructor and then I have a command to modify the EmployeeID (from Employee class) and Name (from Person Class). However, the only UI element in the View that gets updated is the EmployeeID and not the Name (I expected Bob to update to Mike). While debugging I found that PropertyChanged event was always null in my base class (Person). I also noticed that when I remove the whole #INotifyProperty region from my Employee class everything works fine since it is using the Base Type event and methods.The problem I have with that is that all my current model classes implement INotifyPropertyChanged explicitly. They all define a PropertyChanged event and implement the RaisePropertyChanged method, which obviously will impact my bindings in my MVVM application. Lastly, I want to clarify that I do not want wrap my Model properties in my ViewModel and rely on the VM INPC mechanism. I would like to use my Model INPC implementation already in place whithout having to conditionally remove the INPC implementations depending on whether I am inheriting or not from a base type.
In summary, I would like to know what's the best way to implement the INPC in my deeply hierarchical model so that inheritance doesn't break the PropertyEvent propagation as we saw in this example and so my independent classes can be self sufficient as well. Any ideas or suggestions will be greatly appreciated :)
Simply make RaisePropertyChanged protected and move it into the base class. Currently you will have a lot of duplication that is not necessary.
Something like this:
protected virtual void RaisePropertyChanged(string propertyName);
Many MVVM frameworks provide this for you. For example PRISM has a NotificationObject ViewModel base class.
You should only implement INPC once, you can use the same raising method in the subclasses.
I would also change the raise property changed method to use reflection instead of passing in hard coded strings. I see you did it in your view model but not in your models (where most of the errors tend to occur).

how do I access a XAML object from a class other than main?

If I try "var mainpage new Mainpage()"
I will run the mainpage constructor and then all the fields in the XAML object will return to null. How to I access XAML objects in silverlight that are from a different class but part of the same namespace?
Let me explain by example. If you look at the first answer, here is what I am encountering
public class MyPage
{
MyPage()
{
// the constructor makes all the variables from the xaml null
}
public TextBox MyTextBox
{
get { return SomeTextBox; }
}
}
public class SomeOtherClass
{
private void SomeFunction()
{
var page = new MyPage(); // this makes the text empty
var sometext = page.MyTextBox.Text; // so sometext will be empty
}
}
So whatever the user imputs when the program first runs turns to null when I run SomeFunction.
What I am first going to try is to see if when SomeClass is created, the values are put into that class.
If that fails, I am going to try MVVM. I have seen the http://www.vimeo.com/8915487 video and I got the sample mvvm code
Here is the Model:
namespace SimpleMVVM.Model
{
public class SimpleModel
{
// super easy version
//public string SomeSimpleValue { get; set; }
private string _SomeSimpleValue = string.Empty;
// actually do something version...
public string SomeSimpleValue
{
get
{
return "some value";
}
set
{
_SomeSimpleValue = value;
}
}
}
}
here is the view:
and here is the viewmodel.cs
using Simple;
using SimpleMVVM.Model;
namespace SimpleMVVM.ViewModel
{
public class SimpleViewModel : SimpleViewModelBase
{
private SimpleModel MyModel = new SimpleModel();
public string SomeSimpleValue
{
get { return MyModel.SomeSimpleValue; }
set
{
if (MyModel.SomeSimpleValue != value)
{
MyModel.SomeSimpleValue = value;
RaisePropertyChanged("SomeSimpleValue");
}
}
}
}
}
Using this example, I am wondering if it will just as easy as injecting a ViewModel and then changing the bindings in the Model and the View.
Is MVVM really this easy?
There is one more. It is the viewmodel base class
using System.ComponentModel;
namespace Simple
{
public class SimpleViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string PropertyName)
{
var e = new PropertyChangedEventArgs(PropertyName);
PropertyChangedEventHandler changed = PropertyChanged;
if (changed != null) changed(this, e);
}
}
}
OK, so now the hard part. If I create a new class. How do I get the data from the viewmodel class?
First, let me get this rant out of the way: what you propose is very bad design. It fits the definition of smelly code.
If you insist on doing it this way, the "best" approach to take is to declare some public variables on your page that return the actual UI elements.
<UserControl x:Class="MyNamespace.MyPage" ...>
<Grid>
<TextBox x:Name="SomeTextBox" Width="100" />
</Grid>
</UserControl>
public class MyPage
{
public TextBox MyTextBox
{
get { return SomeTextBox; }
}
}
public class SomeOtherClass
{
private void SomeFunction()
{
var page = new MyPage();
page.MyTextBox.Text = "some text";
}
}
Of course the preferred method would be to use something like the MVVM pattern to implement binding from your window to its viewmodel, then you can just read the property values from the viewmodel, this way you avoid trying to touch any UI elements from a totally different class.
Another way to do it (without going the full MVVM route) is to inject the necessary values into the constructor of the control/page that you are instantiating, and from there you can assign them to the appropriate UI element properties. This is still smelly, but better than directly accessing the UI elements from the outside.

Categories

Resources