![Creative The name of the picture]()
Cast Binding Path so it recognises ViewModel property at Design-Time
Ok this is more of an annoyance than a problem. There is no error
Page
<ContentPage
...
x:Name="This"
//hack to have typed xaml at design-time
BindingContext="{Binding Source={x:Static viewModels:ViewModelLocator.ChooseTargetLocationVm}}"
SubView
<views:ProductStandardView
...
BindingContext="{Binding Product}">
<Grid.Triggers>
<DataTrigger
Binding="{Binding Path=BindingContext.IsVacate, Source={x:Reference This}}"
TargetType="Grid"
Value="true">
<Setter Property="BackgroundColor" Value="{StaticResource WarningColor}" />
</DataTrigger>
</Grid.Triggers>
When Binding to BindingContext from the Source Reference of This, i get a XAML "warning"
BindingContext
This
Cannot resolve property 'IsVacate' in data context of type 'object'
Binding="{Binding Path=BindingContext.IsVacate, Source={x:Reference This}}"
Obviously the BindingContext is an object and untyped. However the above code compiles and works
What i want to do is cast it, firstly because i have OCD, however mainly because its easy to spot real problems on the IDE page channel bar
The following seems logical but doesn't work
Binding="{Binding Path=BindingContext.(viewModels:ChooseTargetLocationVm.IsVacate),
Source={x:Reference This}}"
In the output i get
[0:] Binding: '(viewModels:ChooseTargetLocationVm' property not
found on
'Inhouse.Mobile.Standard.ViewModels.ChooseTargetLocationVm', target
property: 'Inhouse.Mobile.Standard.Views.ProductStandardView.Bound'
viewModels:ChooseTargetLocationVm
Inhouse.Mobile.Standard.ViewModels.ChooseTargetLocationVm
Inhouse.Mobile.Standard.Views.ProductStandardView.Bound
I understand the error, yet how else would i cast?
And just for stupidity, obviously the following wont compile
Binding="{Binding Path=((viewModels:ChooseTargetLocationVm)BindingContext).IsVacate, Source={x:Reference This}}"
So is there a way to cast a BindingContext to a ViewModel so any SubProperty references are typed at design time?
Update
This is relevant for inside a DataTemplate or in this case when the control has its own BindingContext which is why i need to use the Source={x:Reference This} to target the page.
DataTemplate
BindingContext
Source={x:Reference This}
Note : <ContentPage.BindingContext> doesn't work for me as i'm using prism and unity and it doesn't seem to play with well a default constructor on initial tests, though i might play around with this some more
<ContentPage.BindingContext>
This question has not received enough attention.
Path=IsVacate
1 Answer
1
You can extend ContentPage to create a generic type - that supports typed parameter for view-model - which in turn can be used in Binding markup extension.
ContentPage
Binding
Although it may not give you intelisense like support - but should definitely remove the warning for you.
For e.g.:
/// <summary>
/// Create a base page with generic support
/// </summary>
public class ContentPage<T> : ContentPage
{
/// <summary>
/// This property basically type-casts the BindingContext to expected view-model type
/// </summary>
/// <value>The view model.</value>
public T ViewModel { get { return (BindingContext != null) ? (T)BindingContext : default(T); } }
/// <summary>
/// Ensure ViewModel property change is raised when BindingContext changes
/// </summary>
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
OnPropertyChanged(nameof(ViewModel));
}
}
<?xml version="1.0" encoding="utf-8"?>
<l:ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:l="clr-namespace:SampleApp"
x:TypeArguments="l:ThisPageViewModel"
x:Name="This"
x:Class="SampleApp.SampleAppPage">
<Grid Margin="20">
<ListView ItemsSource="{Binding Path=Items}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding ViewModel.PropA, Source={x:Reference This}}" />
<Label Text="{Binding}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</l:ContentPage>
Code-behind
public partial class SampleAppPage : ContentPage<ThisPageViewModel>
{
public SampleAppPage()
{
InitializeComponent();
BindingContext = new ThisPageViewModel();
}
}
View model
/// <summary>
/// Just a sample viewmodel with properties
/// </summary>
public class ThisPageViewModel
{
public string PropA { get; } = "PropA";
public string PropB { get; } = "PropB";
public string PropC { get; } = "PropC";
public string Items { get; } = new { "1", "2", "3" };
}
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
How about just setting the binding path to the desired property
Path=IsVacate?– Nkosi
2 days ago