How to bind a view model property to a XAML control - xamarin

Please let me know if Ill be able to bind a property value of a view model to a XAML control.
XAML:
<Emtry x:Key="addressLine1" />
ViewModel:
public string addressLine1 { get; set; }
Is it possible to create a two way binding?

You will have to do it like this: <Entry Text="{Binding addressLine1, Mode=TwoWay}" />
The x:Key doesn't have much to do with it. You will have to bind to the property of the control that you want to use. In this case, on the Entry you want to bind it to the Text property so you can show it to the user and the user can edit it.
Then with the notation of {Binding addressLine1, Mode=TwoWay} you specify which property of the view model to bind to and what the mode should be. You can leave the mode out, then it will have the default value which is OneWay most of the time.
To make the connection between the XAML and the view model, you will still have to specify the DataBinding property on the code-behind of the XAML page.

<Entry x:Name="entAddress" Text="{Binding addressLine1}"/>

Related

How can I set the BindingContext of each view in a CarouselView?

I'm trying to let each view in a CarouselView have the same BindingContext object as the parent ContentPage. I've tried the following which doesn't seem to work. MainPage.xaml is the page that is initialized at runtime. It holds a CarouselView with four ContentViews holding "pages" of functionality I can swipe back and forth between from the MainPage.
MainPage.xaml:
...
<CarouselView Grid.Row="1" Grid.ColumnSpan="4"
Position="{Binding CarouselPosition}"
HorizontalScrollBarVisibility="Never">
<CarouselView.ItemsSource>
<x:Array Type="{x:Type ContentView}">
<local:HomeView></local:HomeView>
<local:NewsView></local:NewsView>
<local:ChartsView></local:ChartsView>
<local:SettingsView></local:SettingsView>
</x:Array>
</CarouselView.ItemsSource>
<CarouselView.ItemTemplate>
<DataTemplate>
<ContentView Content="{Binding .}" BindingContext="{Binding BindingContext, Source={x:Reference mainPage}}"/>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
...
Basically, I want to be able to set the BindingContext for each of these ContentViews to be the same as the parent's. I've also read that the ContentViews should be able to inherit the BindingContext sometimes, but it doesn't seem to be happening in this situation.
Thanks.
This is because this kind of control doesn't inherit its BindingContext from its parent but it has its own BindingContext set to the item of the collection binded to the ItemsSource which makes sense.
Let's say you want to display a collection of User. The DataTemplate will be the user interface of a User. You want to display some properties of a User, not your ViewModel.
If you want to bind to something exposed in the ViewModel and not the User, you have to bind the BindingContext of your element with either a RelativeSource or by targeting an element by its x:Name.
Exemple : to bind a button inside your DataTemplate to a command exposed in your ViewModel (not in User), you need to do that :
<Button
Text="Try me"
Command="{Binding
Path=BindingContext.MyViewModelCommand,
Source={x:Reference xNameOfParentOutsideDataTemplateOrThePage}" />
To make it easier to understand, what it does is : I want to bind to something on the control called xNameOfParentOutsideDataTemplateOrThePage (x:Name="xNameOfParentOutsideDataTemplateOrThePage"). On this control, I want to a property of its BindingContext (most of the time, your view model).
Instead of x:Reference, you can also use a RelativeSource binding.

Windows Phone list picker with empty default value

I have scenario where I need to select country from drop down or list picker. I have found how to make this list, but I need to have a default value in this drop-down and I want the default value to be null.
Can someone suggest the best way how to make something like this.
You should bind the SelectedItem value of the drop-down control to a Property in your ViewModel, then avoid setting the property to other than default value in constructor.
This way it will not show any other item, because your SelectedItem property is null.
EDIT:
If I understand you correctly you could do something like this (I'm using Windows Phone Toolkit at http://phone.codeplex.com/
<toolkit:ListPicker ItemsSource="{Binding MyList}" SelectedItem="{Binding MySelectedItem, Mode=TwoWay}" />
Then your ViewModel could lokk like this:
public ObservableCollection<string> MyList{get;set;}
public string MySelectedItem{
get{ return _mySelectedItem; }
set{ _mySelectedItem = value;
OnPropertyChanged("MySelectedItem");
}

Separate viewmodel for page with Pivot into individual viewmodels

I am using MVVMLight, i have created standard view and viewmodel. In view i have placed Pivot:
<Grid x:Name="LayoutRoot" Background="Transparent">
<controls:Pivot Title="MY APPLICATION">
<local:FirstPivotItem />
<local:SecondPivotItem />
</controls:Pivot>
</Grid>
Here how my Pivot item looks like:
<controls:PivotItem x:Class="Pivot.WindowsPhoneControl1"
xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
// standard references and settings
d:DesignHeight="480" d:DesignWidth="480" Header="First One">
<Grid x:Name="LayoutRoot">
</Grid>
</controls:PivotItem>
In code-behind
public partial class WindowsPhoneControl1 : PivotItem
{
public WindowsPhoneControl1() {
InitializeComponent();
}
}
I want to create viewmodel for this pivot item, and then work with it as i do with standard views.
I will use
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<mvvm:EventToCommand Command="{Binding PivotChangedCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
to handle selection changing event and than inform appropriate viewmodels by Messanger.
I do not know how can i use possibilities of viewmodel in Pivot Item class, that is inherited from PivotItem but not from ViewModelBase, as i need.
Use the standard PivotItem control for the individual items and put user controls inside each of them. Each user control can then have its viewmodel as the data context.
<Grid x:Name="LayoutRoot"
Background="Transparent">
<controls:Pivot Title="MY APPLICATION">
<controls:PivotItem Header="first">
<local:PivotUserControl1 />
</controls:PivotItem>
<controls:PivotItem Header="second">
<local:PivotUserControl2 />
</controls:PivotItem>
</controls:Pivot>
</Grid>
Depends on whether you know what the pivot items are going to be in advance or if they are dynamically created based on data. I'll assume its the first, judging by what you've written so far.
The way I've done this before is to have a number of PivotItem view models as public properties on the parent viewmodel, one for each pivot.
Then just set the dataContext of each PivotItem to the correct viewmodel property on the parent viewmodel.
this way you may be able to get away without the selection changed event.
You can also subscribed directly to any events on the view models so don't necessarily need to bother with messaging for communication as all communication can go through the parent view model.
The second approach, if you're not sure in advance exactly what pivot items you'll have is to have a collection of PivotItemViewModels on the parent view model- one per pivot item, each inheriting from a common base class or interface. Bind that collection to the ItemSource of the viewmodel.
This is slightly trickier as you then have to determine what control to display but you can do this via a converter, if you have the Templates stored somehwere as a resource :
public class PivotItemToTemplateConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch ((int) value)
{
case 1:
return Application.Current.Resources["Control1Template"];
case 2:
return Application.Current.Resources["Control2Template"];
default:
return Application.Current.Resources["Control3Template"];
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
#endregion
}
you can then create a pivot item template for your pivot items and use the converter to get the correct control within it based on a value. in this case imagine the shared base viewmodel has a property ViewModelId which effctively identifies which control you'll be interested in:
<ContentControl
Content="{Binding}"
ContentTemplate="{Binding ViewModelId,
Converter={StaticResource PivotItemToTemplateConverter }}" />

Panorama Title binding

I'm doing WP7 app using Panorama control and have a problem with binding into Panorama Title property. Is it possible to bind that value out from ViewModel object?
Binding in xaml file:
<controls:Panorama x:Name="prmPanorama" Title="{Binding Voyage.Title}">
Voyage property of ViewModel is a Model entity (with Title property inside) with OnNotifyPropertyChanged event fired every time it changes:
private Voyage _voyage;
public Voyage Voyage
{
get { return _voyage; }
set
{
if (_voyage != value)
{
_voyage = value;
OnNotifyPropertyChanged("Voyage");
}
}
}
When I bind the same property into another control, eg. TextBlock, binding works just fine:
<TextBlock Text="{Binding Voyage.Title}" />
The text shown in that text block is as it should be but on the same time panorama title is not binded right - it's collapsed.
Does anyone tried to do that kind of binding? I have no idea why it doesn't work.
<DataTemplate x:Key="TitleDataTemplate">
<TextBlock Text="{Binding}" />
</DataTemplate>
...
<controls:Panorama Title="{Binding Voyage.Title}"
TitleTemplate="{StaticResource TitleDataTemplate}">
The control template of the panorama control uses a content presenter to display whatever value the its title property has kind of like a button. When setting the title template property, you indirectly set the content template of the content presenter.
That is why you have to set the title property on the panorama control and then can use that value in your title template for binding. In other words its not enough to just bind to the title you have to give it a template.
Check out this link for more info

In Prism (Composite Application Guidelines), how can I get views dynamically loaded into TabControl?

In a Prism v2 application, I define two regions, each a tabitem in a tabcontrol:
<UniformGrid Margin="10">
<TabControl>
<TabItem Header="First" Name="MainRegion" cal:RegionManager.RegionName="MainRegion"/>
<TabItem Header="Second" Name="SecondRegion" cal:RegionManager.RegionName="SecondRegion"/>
</TabControl>
</UniformGrid>
In the bootstrapper two modules are loaded and each injects a view into each of the tabitems:
protected override IModuleCatalog GetModuleCatalog()
{
ModuleCatalog catalog = new ModuleCatalog();
catalog.AddModule(typeof(SecondModule.SecondModule));
catalog.AddModule(typeof(HelloWorldModule.HelloWorldModule));
return catalog;
}
Now, of course, I want to perform the decoupling magic that I keep reading about and uncomment one of the modules and see its tab item not appear at all. Instead, on the contrary, there are still two TabItems and one is empty. This tells me that my application is still tightly coupling data and UI as in the bad old WinForm days.
So what do I need to do here to make this dynamic, so that the UI changes dynamically based on what modules are loaded, i.e. so that I could load 10 modules/views in my bootstrapper and there would automatically be 10 TabItems in the TabControl?
INTERMEDIATE ANSWER:
If I just make one region in a TabControl:
<TabControl Name="MainRegion" cal:RegionManager.RegionName="MainRegion"/>
and then load both controls into the MainRegion:
public void Initialize()
{
regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.SecondView));
}
...
public void Initialize()
{
regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.HelloWorldView));
}
then I get a TabControl with two tabs, each with a view in it, which is what I want.
But the TabItem headers are not defined. How do I dynamically define the header (e.g. not in the XAML but dynamically back in the View classes)?
This works too:
public class View : UserControl
{
public string ViewName { get; set; }
}
and then in the shell:
<Window.Resources>
<Style TargetType="{x:Type TabItem}" x:Key="TabItemRegionStyle">
<Setter Property="Header" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.ViewName}" />
</Style>
</Window.Resources>
...
<TabControl cal:RegionManager.RegionName="RightRegion" Width="Auto" Height="Auto" HorizontalAlignment="Stretch" Grid.Column="2"
x:Name="RightRegion" ItemContainerStyle="{StaticResource TabItemRegionStyle}" />
Nice.
You can remove the ViwewName property on the view and change the binding on the TabItem value to be Value="{Binding DataContext.HeaderInfo}" ... where HeaderInfo is a property of your DataContext object - IE the business object which the Tab Item represents. This is a little more elegant.
You are on the right track with your modification.
The way I usually achieve the header is by adding an object to the region instead of a control, and datatemplating it with the control.
This object defines a property (let's say MyHeaderProperty) which I then use to bind to using an ItemContainerStyle on the TabControl.
I do not know if there is a way to achieve that without resorting to that kind of trick (an intermediate object and a DataTemplate).

Resources