Talk to the View
Posted on April 16, 2019 • 2 minutes • 353 words
There are many scenarios where a UI component might not have a Command or bindable property available for certain features that you need to access from the view model. There is a simple, but powerful, thing you can do to allow this and not break MVVM or testing capability, leverage the Interface.
Scenario
Let’s imagine the scenario where we have a special ListView control that has a HighlightItem method that can only be called with a direct reference to that control. There isn’t a Command or DependencyProperty (aka BindableProperty in Xamarin.Forms) alternative, so it has to be done in the code behind.
To keep this simple, here’s the page XAML…
<Page x:Class="MyPage">
<Page.DataContext>
<MyPageViewModel x:Name="ViewModel" />
</Page.DataContext>
<SpecialListView x:Name="MyListView" />
</Page>
…and here is the page code behind.
public partial class MyPage : Page
{
public MyPage()
{
InitializeComponent();
// The only way to use HighlightItem method is in the code-behind
MyListView.HighlightItem(itemToHighlight);
}
}
As you can see, the HighlightItem method has to be used in the code behind because it has a reference to ‘MyListView’. However, you need to use it in the view model, like this:
public class MyPageViewModel
{
private void PleaseHighlightItemNow()
{
// But, you need to highlight the item from view model
}
}
Solution
One solution for this is to define an interface.
public interface IHighlightableView
{
void Highlight(object item);
}
With this, you can add a property to the view model and invoke the method:
public class MyPageViewModel
{
public IHighlightableView View { get; set; }
private void PleaseHighlightItem()
{
// Call the method on the interface!
View?.Highlight(itemToHighlight);
}
}
Now, the interface can be implemented on the page to complete the circle
public partial class MyPage : Page, IHighlightableView
{
public MyPage()
{
InitializeComponent();
// Assign this page instance to the view model
ViewModel.View = this;
}
private void Highlight(object itemToHighlight)
{
// Now you can directly use the UI component's method
MyListView.HighlightItem(itemToHighlight);
}
}
Summary
This is a simple approach that will work if you don’t want to (or are not allowed to) use an existing MVVM framework’s built-in DependencyInjection and IoC features. Enjoy!