0
votes

I have the following XAML. I'm using UWP (Universal Windows Platform) but the problem I'd like to describe also applies to other XAML frameworks such as WPF:

<!-- MyVM is a ViewModel -->
<AutoSuggestBox
    QueryIcon="Find"
    TextChanged="{x:Bind MyVM.FilterTextChanged}" 
    Text="{x:Bind MyVM.FilterText, Mode=TwoWay}"/>

This is how it works: when the user types text in the AutoSuggestBox, MyVM ViewModel is informed about every key stroke and filters data using FilterText.

This is how MyVM looks like:

// Uses INotifyPropertyChanged from MVVMLight
private string filterText;
public string FilterText
{
    get { return filterText; }
    set { Set(ref filterText, value); }
}

public async void FilterTextChanged()
{
    await LoadData(); // uses FilterText to filter data
}

The problem arises when I need to modify FilterText value, for example to clear it or to set a pre-defined filter. Thanks to the TwoWay binding, the text in the AutoSuggestBox is displayed correctly but as a "side-effect" the FilterTextChanged method is called (because the text has changed). I don't want this "side-effect". It is bad from two reasons:

  1. It makes the ViewModel dependent on XAML in the View. What I mean by that is that although I don't call FilterTextChanged, it is called anyway when I set the FilterText value just because it is TwoWay-bound in XAML.

  2. It makes automated unit testing impossible. Without XAML, the ViewModel behaves differently: the FilterTextChanged method is not called when I set a FilterText value.

This is a general problem with XAML, MVVM, and TwoWay binding, not restricted to the specific example with AutoSuggestBox.

How to solve this problem? The main question for me is how to unit test it?

1

1 Answers

0
votes

The problem arises when I need to modify FilterText value, for example to clear it or to set a pre-defined filter. Thanks to the TwoWay binding, the text in the AutoSuggestBox is displayed correctly but as a "side-effect" the FilterTextChanged method is called (because the text has changed). I don't want this "side-effect".

If I understand your question, you just do not want the FilterTextChanged called when you empty the AutoSuggestBox or set a default value for it. If so, you do not need to use TextChanged to trigger the FilterTextChanged method, you could call it when the property value changed.

For example:

<AutoSuggestBox QueryIcon="Find" Text="{x:Bind MyVM.FilterText, Mode=TwoWay}"/>
private string filterText;
public string FilterText
{
    get { return filterText; }
    set
    {
        if (value != string.Empty || value != "default value")
        {
            FilterTextChanged();
        }
        filterText = value;
        RaisePropertyChanged("FilterText");
    }
}

public async void FilterTextChanged()
{
    await LoadData(); // uses FilterText to filter data
}