I am currently working on a UWP application and I would like to use the compiled binding system.
I have a base that extends the Windows.UI.Xaml.Controls.Page
that contains a property ViewModel
.
Here the base class of the ViewModel
Property :
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaiseOnPropertyChanged([CallerMemberName] string propertyName = "")
{
OnPropertyChanged(propertyName);
}
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And here my base page :
public abstract class BasePage : Page
{
public BaseViewModel ViewModel { get; set; }
}
The pages of my app extends the BasePage
and contain a nester (inner) class that extends the BaseViewModel
class. Here a sample code :
public sealed partial class MyPage : BasePage
{
public sealed class MyViewModel : BaseViewModel
{
public string Title
{
get
{
return "Test";
}
}
}
public MyPage()
{
InitializeComponent();
ViewModel = MyViewModel();
}
}
Now, I would like to bind the property Title
of the MyViewModel
class to my UI. According to this article and this one, something like that should work :
<TextBlock
Text="{x:Bind ViewModel.(namespace:MyPage+MyViewModel.Title)}"
/>
Unfortunately, I cannot compile. I have several errors on the generated file MyPage.g.cs
due to the "+" char. Do you know if the binding on a nested (inner) class is supported in UWP application ? Perhaps it is supported only on WPF app ? :(
Thank you for your help !
The solution is to use a new property in order to avoid the cast and the nested class access into the XAML file. So the solution is to use something like :
public sealed partial class MainPage : BasePage
{
public sealed class MyViewModel : BaseViewModel
{
public string Title
{
get
{
return "Test";
}
}
}
public MyViewModel LocalViewModel
{
get
{
return (MyViewModel) ViewModel;
}
}
public MainPage()
{
this.InitializeComponent();
ViewModel = new MyViewModel();
}
}
So, using the x:Bind
syntax, the XAML looks like :
<TextBlock Text="{x:Bind LocalViewModel.Title}" />
There is some problem while casting with "+" char in {x:Bind}
. While using {x:Bind ViewModel.(local:MyPage+MyViewModel.Title)}
in MyPage.xaml, it generates code like following in MyPage.g.cs to update bound data:
private void Update_ViewModel(global::UWP.BaseViewModel obj, int phase)
{
if (obj != null)
{
if ((phase & (NOT_PHASED | (1 << 0))) != 0)
{
this.Update_ViewModel__local_MyPage+MyViewModel_Title_(((global::UWP.MyPage.MyViewModel)(obj)).Title, phase);
}
}
}
private void Update_ViewModel__local_MyPage+MyViewModel_Title_(global::System.String obj, int phase)
{
if((phase & ((1 << 0) | NOT_PHASED )) != 0)
{
XamlBindingSetters.Set_Windows_UI_Xaml_Controls_TextBlock_Text(this.obj2, obj, null);
}
}
Although the cast generated is right, but the method name Update_ViewModel__local_MyPage+MyViewModel_Title_
is invalid. So casting nested class in {x:Bind}
is not supported by now.
If you want to use {x:Bind}
, you can use MyViewModel
instead of BaseViewModel
as following, it will work well.
In the code-behind:
public sealed partial class MyPage : BasePage
{
public MyViewModel myViewModel;
public sealed class MyViewModel : BaseViewModel
{
public string Title
{
get
{
return "Test";
}
}
}
public MyPage()
{
InitializeComponent();
myViewModel = new MyViewModel();
}
}
In the XAML:
<TextBlock Text="{x:Bind myViewModel.Title}" />
Also, if you want to use BaseViewModel
, you can use {Binding}
instead of {x:Bind}
since {Binding}
uses general-purpose runtime object inspection.
In the code-behind:
public sealed partial class MyPage : BasePage
{
public sealed class MyViewModel : BaseViewModel
{
public string Title
{
get
{
return "Test";
}
}
}
public MyPage()
{
InitializeComponent();
ViewModel = new MyViewModel();
this.DataContext = this;
}
}
In the XAML:
<TextBlock Text="{Binding ViewModel.Title}" />