1

I am converting a C# WPF app to MVVM pattern and have couple questions:

I have a ViewModel tied to a Model with constructor requiring parameter that is result of selecting a single object from a JSON list returned to a search query. I suppose this means I cannot instantiate this ViewModel until search is performed.

This was not an issue previously as I didn't need to have a View databound to a ViewModel, and only collected text values from GUI to instantiate the object (Model) when all data is in place and I am ready to do something with it.

With MVVM, this is an issue, since I don't want to force this search to be the first user operation--the user should be able to modify any field in the GUI that is bound to the ViewModel.

What are some practical way of handling this type of situation? Seems I must either: a) wait for a search result to be selected before instantiating the VM or b) remove the parameter from the constructor and instead create a method that would be invoked on the instantiated VM for calculating/setting the properties that would otherwise be set by the constructor.

Second question: how can I implement the Search functionality--that is, how do I stage the List of results after search button is clicked? Previously I would deserialize the list in the SearchButton_Click method, and set the binding of a combobox to the resulting collection. With MVVM, I am having trouble picturing the state between return of result list and selection of the individual result. Do I create a separate ViewModel containing an empty list of target type bound to a combobox and a SearchTerm property bound to the Search TextBox and populate the combobox from the SearchButton Command ICommand? How do I then bind the selected item to my original viewmodel?

ViewModel:

class ObjectViewModel
{
    public CustomObject data;
    public ICommand Search;

    public ObjectViewModel()
    {
        this.data = new CustomObject();
    }
}

Model:

[DataContract]
public class User
{
    [DataMember(Name = "EmailAddress")]
    public string EmailAddress { get; set; }
    [DataMember(Name = "FirstName")]
    public string FirstName { get; set; }
    [DataMember(Name = "FullName")]
    public string FullName { get; set; }
    ...
}


[DataContract]
public class CustomObject
{
    public User Owner;
    ...
}

View (not yet rewritten):

<TextBox Margin="5,0" Name="Owner"></TextBox>
<Button Name="Search" Content="Lookup" Click="OwnerLookUp_Click"></Button>
<ComboBox Name="OwnerMatches" SelectionChanged="OwnerMatches_SelectionChanged" Visibility="Hidden"/>

OwnerLookUp_Click takes text from Owner textbox and returns ObservableCollection and binds it to OwnerMatches. OwnerMatches_SelectionChanged sets Owner textbox to the selected item's Fullname property.

In this scenario, what am I going to bind to data.Owner in the ObjectViewModel?

1
  • Dude, too much text and no sample code. I won't read thru all this. BTW, MVVM is not a problem, non-MVVM is. Commented Sep 11, 2013 at 19:32

2 Answers 2

2

You view model should represent the business logic and state for your view. So in regards to your first question, if it is a valid state for your view to not have a search, then it should not be a constructor argument to the view model. Instead it should probably be a property.

Typically in WPF you would bind a button via a command to a some sort of ICommand on your view model (I usually used DelegateCommand). That command should execute the search and then update the view model's state appropriately. Meaning, it should do the search, gather the results, and set the value of property related to the search results with the data it gathered.

The benefit here is that assuming you have some UI components bound to those search results, as soon as your command has completed your UI is automatically refreshed with the results with no additional code.

UPDATE

In response to your comment: Everything should be bound to your view model, and your view model uses those bindings both to do the work it needs and to update the view.

So your text box Owner should be bound to a property, and then your ICommand would look something like this:

private void ClickCommandExecute() 
{
      var results = searchHelper.SearchFor(this.Owner);
      this.ComboSource = results;
}

Likewise, your combo box's SelectedValue property would be bound to another property on your view model. In your property's setter, you can react to the selection change:

public string SelectedResult
{
    get { ... }
    set 
    {
        _selectedResult = value;
        OnSelectedResultChanged(); // Go do what you need to do here
    }
 }
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the reply! I don't think this fully answers my second question. The user has to select an item from the result--I think that means I need to have two Commands and to store the List in the ViewModel. Please see Question updated with code.
1

Well, you're right in thinking that you would move the parameter out of the constructor. This makes sense because your VM should represent the data that backs up the view. So it should have a list of items for the drop down menu, strings for the labels, etc. And when search is pressed, you can then actually perform the search and deserialize the result as you would in MVC.

To get it onto the UI, have the ComboBox bound to a property on the View Model that is a list. This list will be what you assign to when the deserialization is complete. By assigning to this variable, you will update the UI, and voila.

public class MyViewModel : INotifyPropertyChanged
{
    private ObservableCollection<string> _retrievedItems;
    private string _selectedItem;

    public ObservableCollection<string> RetrievedItems
    {
        get
        {
            return _retrievedItems;
        }
        set
        {
            _retrievedItems = value;

            OnPropertychanged("RetrievedItems");
        }
    }
    public string SelectedItem
    {
        // same as other property, but with _selectedItem
    }


    public MyViewModel()
    {
        // Do whatever you normally do to initialize the view model
    }

    public void Search(string searchParamThatWasInConstructor)
    {
        // do something to get results (deserialization)
        // var results = new JavascriptSerializer( ).Deserialize<List<string>>( searchParamThatWasInConstructor );
        // That's just a fake example

        RetrievedItems = new ObservableCollection<string>(results);
        SelectedItem = RetrievedItems.Count > 0 ? RetrievedItems[0] : string.Empty;
    }
}

And bind your combo box as follows:

<ComboBox ItemsSource="{Binding RetrievedItems}" SelectedItem="{Binding SelectedItem}" />

2 Comments

Thanks! Please see Question updated with code--which UI control containing the selected result do I bind to (in your sample) MyViewModel?
Check out the updated code I posted; this should answer that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.