Xamarin xaml binding - xaml

I am trying to bind my xaml to a property in my view model, but it doesn't work as I expected.
The following code works, but it seems to create a new instance of the mainwindowviewmodel object which will result in problem.
<Label Text="{Binding Path=Test}" >
<Label.BindingContext>
<local:MainWindowViewModel />
</Label.BindingContext>
</Label>
The following doesn't work at all.
<Label Text="{Binding Path=Test}" >
</Label>
I've the property Test in my view model.
What am I doing wrong?

Make sure to set the BindingContext of the View to an instance of the model (MainWindowViewModel) to make the second code snippet work.
For example in the constructor of the view's code behind
public MainWindow() {
InitializeComponents();
var viewModel = new MainWindowViewModel();
this.BindingContext = viewModel;
}
Or directly in the View
<MainWindow.BindingContext>
<local:MainWindowViewModel />
</MainWindow.BindingContext>
The both above are technically equivalent.

Related

Localize strings in XAML UI in UWP

I have a resource entry named info_278 in the Resources.resw file on my UWP app. I have 3 scenarios where I need to use this resource but looks like I need to duplicate this to cater to different scenarios. Scenarios are as follows.
Error message content from code
var displayErrorOnPopup = ResourceHandler.Get("info_278");
TextBlock Text property from XAML (Looks like a new entry needed as info_278.Text)
<TextBlock x:Uid="info_278" Margin="10,0,0,0" />
Button Content property from XAML (Looks like a new entry needed as info_278.Content)
<Button x:Uid="info_278" Margin="10,0,0,0" />
How do I proceed without duplicating this resource in the .resw file?
The only way to avoid duplication is to set the string value in code-behind using ResourceLoader. Because you could direct access to the specific property of the target control. Like this:
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
this.TextBlock.Text = resourceLoader.GetString("info_278");
If you are not going to do it in the code behind, then I have to say there is no way to avoid the duplication of the resource string. You should add info_278.Text and info_278.Content for different XAML scenarios.
You could create a markup extension. I've used this in WinUI 3, but should work in UWP too.
using Microsoft.UI.Xaml.Markup;
using Windows.ApplicationModel.Resources;
namespace MyApp;
[MarkupExtensionReturnType(ReturnType = typeof(string))]
public class StringResourceExtension : MarkupExtension
{
private static readonly ResourceLoader _resourceLoader = new();
public StringResourceExtension() { }
public string Key { get; set; } = "";
protected override object ProvideValue()
{
return _resourceLoader.GetString(Key);
}
}
Then in the XAML:
...
local="using:MyApp"
...
<TextBlock Text="{local:StringResource Key=info_278}" />
<Button Content="{local:StringResource Key=info_278}" />
The Content of Button can be a TextBlock:
<Button>
<TextBlock x:Uid="MyTextId" Style="{StaticResource MyTextBlockStyle}" />
</Button>

How can I access a property from a ViewModel to a ButtonClickEvent which is inside the CodeBehind of Xaml View?

I want to access the properties created in ViewModel to the xaml code behind file. Please have a look at the attached screenshot for better understanding on my question.
Please Click Here to View the Screenshot of my Xaml code
Click Here for the Properties code
I have bind the "EntryText" property to an Entry field and "LblText" property to a Label. So, now I just want to transfer the value of Entry to the Label on a button click event.
You're on the right track, just need to search slightly differently.
There's multiple ways of doing this. I will tell you the simplest way since that's also suggested in the Xamarin Official Docs. So your Xaml code will look like this
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ButtonDemos.BasicButtonClickPage"
Title="Basic Button Click">
<StackLayout>
<Label x:Name="label"
Text="Click the Button below"
FontSize="Large"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
<Button Text="Click to Rotate Text!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center"
Clicked="OnButtonClicked" />
</StackLayout>
</ContentPage>
And your C# file would look like this
public partial class BasicButtonClickPage : ContentPage
{
public BasicButtonClickPage ()
{
InitializeComponent ();
}
async void OnButtonClicked(object sender, EventArgs args)
{
await label.RelRotateTo(360, 1000);
}
}
You can use code-behind to invoke a method in the view model. So in that method, you can change the LblText. Refer below code.
<Button x:Name="btn1" Clicked="btnClicked" />
In code-behide
private void btnClicked(object sender, EventArgs e){
_viewModel.ChangeLabelText();
}
In the View Model
public void ChangeLabelText() {
LblText = EntryText;
}
You can use the page's BindingContext and cast it to your model. And, then access the property from there.
var myModel = this.BindingContext as MainPageProperties;
if(myModel!=null)
{
//Access your property here!
var text = myModel.LblText;
}

Xamarin TabbedPages MVVM Binding

How to bind tabbed page with different view models?
To make it clearer I have this tabbed page:
<TabbedPage.Children>
<tabPages:Page1/>
<tabPages:Page2/>
<tabPages:Page3/>
</TabbedPage.Children>
These 3 pages have different view models. However, the problem is the view models of each pages won't bind. Is there a specific way in order to do this?
To test if my view models for each pages works, I inlined the code in tabbed page:
e.g.
<TabbedPage.Children>
<ContentPage Title="Test">
<Label Text="{Binding TestBind}"/>
</ContentPage>
</TabbedPage.Children>
And for bind it to the view model of the tabbed page (parent) - this method works. However, if I do it separately, the view models wouldn't bind.
E.g.
public class Page1ViewModel : BaseViewModel
{
public Page1ViewModel()
{
TestBind = "Test";
}
private string _TestBind;
public string TestBind
{
get { return _TestBind; }
set { SetProperty(ref _TestBind, value); }
}
}
Using it this way, it wouldn't bind
I've made it worked, so this is what I did:
<TabbedPage.Children>
<views:ChildPage1>
<views:ChildPage1.BindingContext>
<viewModels:ChildPage1ViewModel/>
</views:ChildPage1.BindingContext>
</views:ChildPage1>
<views:ChildPage2>
<views:ChildPage2.BindingContext>
<viewModels:ChildPage2ViewModel/>
</views:ChildPage2.BindingContext>
</views:ChildPage2>
</TabbedPage.Children>
I used binding context property of the element to set it.
Why not just set the BindingContext of each TabPage to each ViewModel:
<TabbedPage.Children>
<tabPages:Page1 BindingContext="{Binding viewModel1}" />
<tabPages:Page2 BindingContext="{Binding viewModel2}" />
<tabPages:Page3 BindingContext="{Binding viewModel3}"/>
</TabbedPage.Children>
Those ViewModels would have to exist as properties in the parent VM.

Xamarin.Forms correct way of Binding in ResourceDictionary Controls

I'm having problems getting this to work.
<ResourceDictionary>
<ViewCell x:Key="Separator">
<Label Text="{Binding Title}" />
</ViewCell>
</ResourceDictionary>
The class Option contains a property named Title which is set to whatever text. However the following code is not working. No text appears in the label. Text just stays "null". What am I doing wrong - how can I set the Binding correctly?
if (Resources.ContainsKey("Separator"))
{
var cell = Resources["Separator"] as Cell;
if (cell != null)
{
cell.BindingContext = option;
section.Add(cell);
}
}
Objects in a ResourceDictionary are created only once, and their instances are shared everytime you use them. As ViewCell and Binding can not be reused, this is unlikely to work.
What you can define in the ResourceDictionary is a DataTemplate containing the ViewCell, and in that case, it can be shared as the DataTemplate content will be recreated for each usage.

Silverlight Data Binding in Nested Controls

Hi guys I am working with SL4 and MVVM application actually i am stuck some where i might be doing some thing wrong thats why need your help, here is my scenario
//suodo code
public class EmployeeModel
{
//code
Public List<Shifts> Employeeshifts{get;set;}
}
public class ShiftModel
{
//code
}
Viewmodel for main page
public class MainVM
{
MainVM()
{
EmployeeList = DateFromSomeService;
}
Public List<Employees> EmployeeList{get;set}
Public DelegateCommand ClickBindingCommand{get;set;}
}
MainPage.xaml
<ItemsControl ItemSource={Binding EmployeeList}>
<ItemTemplate>
<DataTemplate>
<controls:EmployeeControl/>
</DataTemplate>
</ItemTemplate>
</ItemsControl>
Employeecontro.xaml
<ItemsControl ItemSource={Binding EmployeeShifts}>
<ItemTemplate>
<DataTemplate>
<controls:ShiftControl Click={Binding ClickBindingCommand}/>//here is problem this command is in mainviewmodel
</DataTemplate>
</ItemTemplate>
</ItemsControl>
MainPage.cs
this.DataContext = new MainVM();
ClickBindingCommand is defined in main VM but it is bound within shift control and shiftcontrol's data context is shift class which is my model class. If I declare this command in my shift model class than it works, means if I click on shift control this property is called but I dont want this because I want it in my main view model, where am I wrong?
Should I declare it in my shift model class but in this way i will bind directly my model to my view?
Use a DataContextProxy or a RelativeSource Binding. This will allow your Command to bind/fire on your MainViewModel.
Another alternative is to use the Caliburn Micro framework. You can then attach an action to your button in the child and click events will bubble up to the parent.
This "toolkit" offers an implementation of FindAncestor in silverlight. Try this:
http://blog.thekieners.com/2010/09/08/relativesource-binding-with-findancestor-mode-in-silverlight/
I ran into this same issue and what fixed it for me was to name my UserControl then reference that name in the binding.
Here is the syntax:
{Binding ElementName=SomeTextBox, Path=Text}
Bind to the “Text” property of the element XAML
element with name=”SomeTextBox” or x:Name=”SomeTextBox”.
So here is my user control:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SupportReports.Workflow.Portfolio.PortfolioManager"
mc:Ignorable="d"
Name="PortfolioManagerControl"
>
And here is the nested dataTemplate that binds to my command in my main view model
<cmd:EventToCommand Command="{Binding ElementName=PortfolioManagerControl, Path=DataContext.PortfolioManagerProjectSelectedCommand}" CommandParameter="{Binding Text, ElementName=ProjectName}" />