Should I be using BindingBase instead of Binding in the signature of a class that creates a Xamarin Object? - xamarin

I am creating a new object from my Xamarin code like this:
new ArrowGrid("Group Name", new Binding(nameof(_vm.Name))));
and using it like this:
public ArrowGrid(string text1, Binding text2, string tapCommandParam) : this()
{
this.Text1 = text1;
this.SetBinding(ArrowGrid.Text2Property, text2);
}
ReSharper is suggesting that I change to BindingBase:
public ArrowGrid(string text1, BindingBase text2) : this()
Can someone explain to me what the difference is between Binding and BindingBase. Is there any reason to change to BindingBase?

It is similar You could choose by yourself.
The SetBinding method defined by BindableObject has an argument of type BindingBase from which the Binding class derives.
The following example shows how to set a binding to a property via BindingBase.
var label = new Label ();
label.SetBinding (Label.TextProperty, new Binding ("Name"));
There are other SetBinding methods defined by the BindableObjectExtensions class. It creates and applies a binding to a property.
The following example shows how to use the extension method to set a binding. This is a simpler SetBinding extension method from this class.
var label = new Label ();
label.SetBinding (Label.TextProperty, "Name");

Related

In Xamarin.Forms Shell How do I add menuitems programatically

In Xamarin Forms v4.0.0.394984 pre10 using Visual Studio 2017 I was able to add MenuItems to the Shell programatically in the constructor of the Shell using the MenuItemsCollection MenuItems.
Here is the code that works in v4.0.0.394984 pre10 (simplified it for this question to add a single hard-coded menuitem and function LoadView is not shown here)
public partial class Shell : Xamarin.Forms.Shell
{
public ICommand cmdLoadView { get; } = new Command(LoadView);
public Shell()
{
InitializeComponent();
BindingContext = this;
MenuItem mi = new MenuItem();
mi.Command = cmdLoadView;
mi.CommandParameter = "myCommand";
mi.Text = "sampleName";
MenuItems.Add(mi);
}
...
}
In all subsequent versions, this code does not work. Intellisense indicates that MenuItems is still part of the Shell, but I get a compilation error saying:
error CS0103: The name 'MenuItems' does not exist in the current context.
When I reference as this.MenuItems I get the compilation error:
error CS1061: 'Shell' does not contain a definition for 'MenuItems' and no accessible extension method 'MenuItems' accepting a first argument of type 'Shell' could be found (are you missing a using directive or an assembly reference?)
Is this possible in the current version of Xamarin.Forms? I've tried with each of the releases and pre-releases since v4 pre10 and none have worked.
Thanks is advance for any help!
You need to add the MenuItem objects to the Current.Items property in your AppShell implementation. Example:
// factory method to create MenuItem objects
private static MenuItem CreateMenuItem(string title, ICommand cmd)
{
var menuItem = new MenuItem();
menuItem.Text = title;
menuItem.Command = cmd;
return menuItem;
}
public AppShell()
{
...
// you can place this code in any method in the AppShell class
Current.Items.Add(CreateMenuItem("AppInfo", new Command(async () =>
{
ShellNavigationState state = Shell.Current.CurrentState;
await Shell.Current.Navigation.PushAsync(new AppInfoPage());
Shell.Current.FlyoutIsPresented = false;
})));
...
}

Xamarin: set labelText with an instance of ViewModel isnt updating UI

I defined a Label in Xaml
<Label Text="{Binding DeviceGuid}"/>
set the BindingContext inside my Page
BindingContext = new BluetoothViewModel();
and wrote the code for the getter and setter in the ViewModel
private string _deviceGuid;
public string DeviceGuid
{
get
{
return _deviceGuid;
}
set
{
if (_deviceGuid != value)
{
_deviceGuid = value;
OnPropertyChanged();
}
}
}
So thats the simple Thing :). The Binding works if I change the value inside the ViewModel.
Now here it comes:
There are some Backgroundtasks (or just other classes) that, in my opinion, should have Access to that property and if they will write it, the UI should update automatically.
I think its bad practice but I dont know how to realise it different.
I´ve already tried to create another instance of the viewmodel like
BluetoothViewModel a = new BluetoothViewModel();
a.DeviceGuid = "test";
Its calling the OnPropertyChanged() but isnt updating the UI ...
Thanks for your help in advance.
When you do this:
BluetoothViewModel a = new BluetoothViewModel();
a.DeviceGuid = "test";
You are creating another instance of the viewmodel that is not the one in your BindingContext.
Do this instead:
public BluetoothViewModel viewmodel;
BindingContext = viewmodel= new BluetoothViewModel();
And then:
viewmodel.DeviceGuid = "test";
The reason it must be happening is that you are not making these changes in the MainThread which is the thread responsible for making changes on the UI.
Do something like below where you change the property data:
Device.BeginInvokeOnMainThread(() => {
DeviceGuid="New string"; });
Update
What you should be doing is using the BindingContext and creating a new instance so your variable 'a' should look something like below
private BluetoothViewModel viewmodel;
BindingContext = viewmodel= new BluetoothViewModel ();
And then do this
viewmodel.DeviceGuid="New string";

xamarin: binding object and object parent to property change

I have a model "optionModel" with "data" member as a list of "options". Option has title and status members:
class optionModel
{
...
public List<option> data {get; private set;}
}
class option
{
...
public String title{get;set}
public bool status {get;set}
}
My view for the model is a grid, which is populating like this:
optionModel _m = new optionModel();
Grid g = new Grid();
foreach (option op in _m.data)
{
..
TextSwitch tc = new TextSwitch(); // view class
tc.BindingContext = op;
tc.SetBinding(TextSwitch.IsToggledProperty, "status");
g.Children.Add(tc, 0, iRow);
..
}
Everything works as expected. "status" property of the "option" is updated, I am happy.
My question is: In addition to "option" I also want "optionModel" to be notified when any of the "option" change their status. One immediate solution is
to construct the "option" to have pointer to the optionModel and notify optionModel it within "status" set method of "option".
But perhaps there is a way to do it via Xamarin binding mechanism without introducing optionModel as a member of "option"?
Thanks!

How to bind an MVC3 view to a SelectList that is created from an IEnumerable<MyCustomType>

When I try to bind in an MVC 3 view (using an #Html.DropDownList helper) to a select list based on an IEnumerable< X >, where X is a custom class I created rather than a framework class, I get the error “DataBinding: 'MyCustomNamespace.MyCustomClass' does not contain a property with the name 'MyProperty'.”. I do not get an error if I use a SelectListItem or a KeyValuePair in place of my custom class in the IEnumerable - in that case it works fine. I am guessing that the issue may be that my custom class is not known in the Html.DropDownList helper and hence can’t be accessed there? But I thought this was supposed to operate using reflection and the property names I specified during SelectList definition, so that would not be necessary… ?
Here is a simplified version of my code:
// In .cshtml file:
#Html.DropDownList("cmbSection", (SelectList)ViewBag.Section)
// In Controller:
List<MyCustomClass> filters = new List<MyCustomClass>();
MyCustomClass testItem1 = new MyCustomClass { MyProperty = "AAA"};
MyCustomClass testItem2 = new MyCustomClass { MyProperty = "BBB"};
filters.Add(testItem1);
filters.Add(testItem2);
return new SelectList(filters, "AAA", "MyPropertyName", "MyPropertyName");
// Elsewhere:
public class MyCustomClass
{
public string MyProperty
}
Thanks!
controller
//your code starts
List<MyCustomClass> filters = new List<MyCustomClass>();
MyCustomClass testItem1 = new MyCustomClass { MyProperty = "AAA"};
MyCustomClass testItem2 = new MyCustomClass { MyProperty = "BBB"};
filters.Add(testItem1);
filters.Add(testItem2);
//your code ends here
var items= (from item in filters
select new SelectListItem
{
Value= item.MyProperty
Text= item.MyProperty
}).toList();
ViewBag.items= items;
View
#Html.DropDownList("MyDropDownList", items)
Check out Phil Haacked blog Model Binding To A List. He posts almost everything about how the default model binder works with Lists.

How do I correctly bind?

I have a class MyClass, which implements INotifyPropertyChanged, and it has some properties that must be bound in some page. In my page I have
private MyClass myclass;
and in the page constructor I write
ContentPanel.DataContext = myclass;
When I assign myclass to some MyClass object, which I get from some callback, nothing is shown in page.
But when I write the properties that I must change instead of MyClass class in page.cs and bind them it work correctly.
Or when I give
ContentPanel.DataContext = this;
and in xaml I write
{binding this.myclass.property}
it also works correctly.
Here is callback
public void GetCommonInfoCallback(UserCommonInfo userCommonInfo)
{
CommonInfo = userCommonInfo;
}
where UserCommonInfo is MyClass, and CommonInfo is myclass.
private UserCommonInfo userCommonInfo ;
public UserCommonInfo CommonInfo
{
get
{
return userCommonInfo;
}
set
{
if (userCommonInfo != value)
{
userCommonInfo = value;
OnPropertyChanged("CommonInfo");
}
}
}
I can't understand where is my mistake. Can you help me?
When you set DataContext, it is the specific instance of MyClass that is used for data binding. So after executing
ContentPanel.DataContext = myclass;
you could later execute
myclass.someProperty = "new value of someProperty";
and the data will be updated in the bound control (assuming this is not a OneTime binding, but OneWay or TwoWay binding instead).
If I understand you question correctly, you want to change the binding to use a different instance of MyClass.
myclass = new MyClass { /* ... */ }; // new instance of MyClass
At this point, the controls are still bound to the previous instance of MyClass. You can change that by updating the DataContext:
DataContext = myclass; // set context to the new MyClass instance
The second approach that you wrote, with
ContentPanel.DataContext = this;
represents a different style, where you are making the page class also serve as the data model instance for data binding.
In this case, you are not changing the data binding to use a new instance of the data model (the page instance, 'this', is not changing). IMHO, there is very valuable to separate the page and the data model, so I prefer to not use the DataContext = this approach.

Resources