My databinding fails, is the path wrong? - windows-phone-7

I'm trying to create a simple RSS news aggregator. But I've done something wrong with the binding.
The xaml:
<phone:LongListSelector
x:Name="MainLongListSelector"
Margin="0,0,-12,0"
ItemsSource="{Binding Path=News.List}"
SelectionChanged="MainLongListSelector_SelectionChanged">
The code behind:
(mainpage)
public MainPage()
{
InitializeComponent();
// Set the data context of the LongListSelector control
// to the sample data
DataContext = App.ViewModel;
(viewmodel)
public class NewsViewModel : BaseViewModel
{
public NewsRepository News { get; private set; }
}
The NewsRepository is just an model object holding the List<obj> List. Could anyone point me in the direction where thing goes sideways?
The app runs just fine but the single item in the List I've put in manually does not show up in the application :-(
I've set and breakpoint at the assignment of the DataContext to the the viewmodels content its there...

Both NewsViewModel and NewsRepository have to implement INotifyPropertyChanged.
It would be easier if you use ObservableCollection<obj> as a source of your binding instead of custom NewsRepository object.

Related

Xamarin access to entry in other view

I'm developing Multiplatform app through Xamarin.
I'm using custom entry in a separate view and I'm using in some pages of my app
This is my simple code for entry
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="prova.MyView">
<ContentView.Content>
<Entry x:Name="MyEntry"
TextChanged="MyEntry_TextChanged"
Margin="100"/>
</ContentView.Content>
and cs file
public partial class MyView : ContentView
{
public MyView()
{
InitializeComponent();
}
void MyEntry_TextChanged(System.Object sender, Xamarin.Forms.TextChangedEventArgs e)
{
}
}
in my pages I insert entry with this simple code
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="prova.MainPage"
xmlns:pages="clr-namespace:prova">
<StackLayout>
<pages:MyView/>
</StackLayout>
I wonder how can I get when MyEntry_TextChanged is fired in my ContentPage?
one solution is to use MessaggingCenter but I wonder if there's a better and more elegant solution
There are two ways I can think of to do this.
1. Inherit from the Entry class as Jason commented.
public class MyView : Entry
{
public MyView()
{
InitializeComponent();
}
}
This will expose the bindable TextChanged property which you can reference in XAML like you want to do.
2. Create the binding yourself
You can create the binding to a custom "TextChanged" property yourself, but this is more complicated and may achieve the same result with extra effort. You will also need to create a bindable "Text" property. The code below is untested, but uses the bindings I found in the Xamarin.Forms InputView class (which is what Entry derives from). This will be along the lines of what you need to do if you do not do it the way of #1. Exposing bindable properties to XAML will look like this:
public class MyView : ContentView
{
public MyView()
{
InitializeComponent();
}
public string Text
{
get
{
return (string)GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
public static readonly BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(MyView), defaultValue: "", propertyChanged:
(bindable, oldValue, newValue) => ((MyView)bindable).OnTextChanged((string)oldValue, (string)newValue));
public event EventHandler<TextChangedEventArgs> TextChanged;
protected virtual void OnTextChanged(string oldValue, string newValue)
{
TextChanged?.Invoke(this, new TextChangedEventArgs(oldValue, newValue));
}
}
I hope my more comprehensive answer helps you choose the direction you want to go for this. If you want to learn more about Bindable Properties, check out Edward's link.

Dynamic resx translation in Xamarin Forms using MVVM

We have an app written with Pages and no pattern and I want to re-write it using MVVM. Currently we use a Picker for language selection and when the culture changes we set all label.Text controls again in order to redraw them in the new language.
I re-wrote the same page using MVVM and now SelectedItem in the Picker is bound to a Language object. In the setter for SelectedItem I also change the culture of my resx (AppResources.Culture) but the UI bound to it (e.g. Text="{x:Static resources:AppResources.Title) doesn't change language.
Full code in my SelectedItem setter:
SetProperty(ref selectedLanguage, value);
AppResources.Culture = value.Culture;
cultureManager.SetLocale(value.Culture);
How should I update all the Text of my UI? Is there any clean way to do something like this, it seems like a basic translation need... or it wasn't meant to be done, especially not without closing the view/app?
The approaches I found for localization using IMarkupExtension and this thread on Xamarin forums which in the end effectively re-creates the page...
My goal is to ideally reload text without having to re-create the view/close the app, using MVVM and clean code. I have about 10 views so it has to be something reusable.
Create you RESX Resources first. I use en, nl, fr for example.
Create the view model to binding the LocalizedResources.
public class ViewModelBase : INotifyPropertyChanged
{
public LocalizedResources Resources
{
get;
private set;
}
public ViewModelBase()
{
Resources = new LocalizedResources(typeof(LocalizationDemoResources), App.CurrentLanguage);
}
public void OnPropertyChanged([CallerMemberName]string property = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
public event PropertyChangedEventHandler PropertyChanged;
}
In SettingsPage, use a picker to choose the language.
<StackLayout>
<Label Text="{Binding Resources[PickLng]}" />
<Picker ItemsSource="{Binding Languages}" SelectedItem="{Binding SelectedLanguage, Mode=TwoWay}" />
</StackLayout>
View model of SettingsPage.
public class SettingsViewModel : ViewModelBase
{
public List<string> Languages { get; set; } = new List<string>()
{
"EN",
"NL",
"FR"
};
private string _SelectedLanguage;
public string SelectedLanguage
{
get { return _SelectedLanguage; }
set
{
_SelectedLanguage = value;
SetLanguage();
}
}
public SettingsViewModel()
{
_SelectedLanguage = App.CurrentLanguage;
}
private void SetLanguage()
{
App.CurrentLanguage = SelectedLanguage;
MessagingCenter.Send<object, CultureChangedMessage>(this,
string.Empty, new CultureChangedMessage(SelectedLanguage));
}
}
Do not forget to binding the context.
I have upload on GitHub, you could download from DynamicallyBindingRESXResources folder on my GitHub for reference.
https://github.com/WendyZang/Test.git

How to change a property of ViewModel property and make the change reflects on the bound control?

I'm writing a windows Phone app; and as a good citizen I'm using MVVM pattern :) Being not so expert in MVVM, I faced the following issue that I hope I find solution for here.
I have the following code:
XAML
<Grid x:Name="LayoutRoot" Background="Transparent" DataContext="{Binding MyPOCO}">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding IsActive}"/>
</StackPanel>
</Grid>
Code Behind
this.DataContext = new ViewModel();
ViewModel
public class ViewModel : ViewModelBase
{
private POCO myPOCO;
public ViewModel()
{
this.myPOCO = new POCO();
this.ToggleActiveStatusCommand = new RelayCommand(this.ToggleActiveStatus);
}
public POCO MyPOCO
{
get
{
return this.myPOCO;
}
}
public RelayCommand ToggleActiveStatusCommand { get; private set; }
private void ToggleActiveStatus()
{
this.MyPOCO.IsActive = !this.MyPOCO.IsActive;
System.Diagnostics.Debug.WriteLine(this.MyPOCO.IsActive);
this.RaisePropertyChanged("MyPOCO");
}
}
POCO
public class POCO
{
public string Name { get; set; }
public bool IsActive { get; set; }
}
What I'm trying to achieve is to change the TextBlock text as the value of IsActive changes... how to do that? I mean other than exposing the required properties from POCO as properties to ViewModel.
Thanks
I think you will have to implement properties in your ViewModel that call into the POCO properties unless you implement INotifyPropertyChanged in your POCO which then goes against MVVM where your Model should just hold your data and your ViewModel is the glue that links the Model with the View.
Creating properties in your ViewModel may seem like alot of additional work but it does add the benefit of being able to define many ViewModels based on a single Model. So in the specific ViewModel you only expose properties that you need rather than everything the Model can offer you.
Once you have defined your ViewModel properties, you may need to set the Mode of your Binding to TwoWay so that the UI can be updated when the underlying ViewModel properties change.

Why does the data binding source need an explicit getter?

If I don't add explicit accessors to a String property, then data binding doesn't work. Why is that?
Here is a simple example where a text box is hooked up to a String property.
MainPage.xaml:
<Grid Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock Text="{Binding Message} />
</Grid>
And the code behind:
public String Message;
public MainPage()
{
InitializeComponent();
Message = "Hello World";
DataContext = this;
}
This does not work, the text box is empty.
However, add property accessors;
public String Message { get; set; };
And now it works.
I can't see this explained in MSDN Data Binding. Can someone explain it? Don't properties have an implict set/get accessors? Even so, why can't data binding just access the property?
Thanks,
public String Message;
This is a field, not a property. Adding getters and setters creates an auto property.
Only properties can be bound to.
The { get; set; } is what makes the compiler generate those implicit accessors. If you leave that out, you're not creating a property at all, but a simple field.
I'm not into XAML that much so I can't say for sure, but maybe it just doesn't support binding to plain fields.
public String Message; is a field, not a property.
Databinding only works with properties.

Binding to Global variable in Silverlight for WP7

Let's say that I have a global variable defined in App.xaml.cs as follows:
public static MyClass GlobalInstance = new MyClass()
And then in MainPage.xaml I would like to bind to a property of this class like follows:
<TextBlock Text="{Binding App.GlobalInstance.Property1}" VerticalAlignment="Top" Height="31" HorizontalAlignment="Left" Width="80">
Is there something I am missing here? For some reason it does not appear to be properly bound.
Any advice here would be greatly appreciated.
Thanks!
You need to assign your App to DataContext of the page
First way is do this in page constructor:
public MainPage()
{
InitializeComponent();
DataContext = App.Current;
}
And your binding will be
{Binding GlobalInstance.Property1}
The second way is to make a reference to App class in page resources
Also, edit your field implementation to something like this:
public static MyClass GlobalInstance {get; private set; }
...
GlobalInstance = new MyClass();

Resources