user99999991
user99999991

Reputation: 1421

When to separate View from ViewModel?

So I'm working on a GUI and most of it I implemented with 1 window and used the code-behind for that window to handle most of the logic. The program is very GUI driven. Say there is a combo box, if you select something from the combo box, the data drastically changes and all the other GUI boxes/labels/grids change or clear ect ect.

I'm doing a lot of refactoring and I've been aware of MVVM, but I've never really seen the need for it. I understand what and why its used, but functionality its just easier to reference all the GUI components straight from the code behind I've found.

For example...

In my main window I have

<ComboBox x:Name="MyTitlesUI" ItemsSource="{Binding Titles}" SelectionChanged="MyTitlesUI_SelectionChanged">

So the ComboBox is tied to a List Titles in my MainWindowViewModel right? Where should MyTitlesUI_SelectionChanged event go? It needs to go in the View correct? But what if the functionality of SelectionChanged has to do with data inside MainWindowViewModel?

Say you change the selection in MyTitlesUI and now the program has to look up up that Title string in a database. All of that database functionality is in DBClass which you declare in MainWindowViewModel. How do you access that functionality? Why would you have to do this:

In main window cs:

private void MyTitlesUI_SelectionChanged(object sender, EventArgs e)
{
   viewModel.ConnectToDataBase((string)MyTitlesUI.SelectedItem);
}

In MainWindowViewModel.cs

private SelectedTitle;
public void ConnectToDataBase(string title)
{
  SelectedTitle = title;
  DBClass myDB = new DBClass(SelectedTitle);
  .... //do stuff with myDB
 }

That just seems kind of unnecessary no? This is just a mild mild example of course and maybe that seems pretty clean. But if you're doing really complex back and fourth between View and ViewModel, the reference to MyTitlesUI.SelectedItem in View may be needed in ViewModel for other functions to work hence the SelectedTitle private variable.

Now you have more assignments, more variables, more functions that just call other functions than just a simple MyTitlesUI.SelectedItem to deal with.

Why not bring the DBClass reference up to the View or similar? Especially if you're doing a lot of UI manipulation that the information inside your ViewModel will be playing with. Say once I change the selection of Title, I need graph to clear. But my graph can't clear until my ViewModel has connected to the DB or something.

I'm going to have graphs or grids defined in my View that depend on dynamically created data in my ViewModel that needs to update. And I'm trying to wrap around what needs to be in View and what needs to be in ViewModel. It seems to be not proper to reference View from ViewModel, so something like MyTitlesUI.SelectedItem can't be called in ViewModel.

EDIT:

So going back to the Selected Item example, say I have a Treeview UI item. I want to bind that to a Treeview that I don't have yet. I create the data for it procedural with DB connect. So the user selects from the combobox the Title they want. Db Connect then creates, asynchronously, a TreeviewItem in some kind of data structure.

private SelectedTitle;
public void ConnectToDataBase(string title)
{
  SelectedTitle = title;
  DBClass myDB = new DBClass(SelectedTitle);

  if(myDB.doneWorking)
  {
    myTreeView.ItemsSource = myDB.GetTree();
  }

 }

Upvotes: 1

Views: 125

Answers (1)

Fede
Fede

Reputation: 44068

but functionality its just easier to reference all the GUI components straight from the code behind I've found

Wrong. MVVM delivers a clean, Property-based approach that's much easier to work with than the txtPepe_TextChanged() winforms-like approach. Try to change the Text for a TextBlock buried deep inside a DataTemplate that is used as the ItemTemplate of a Virtualized ItemsControl using code behind... WPF is not winforms.

Where should MyTitlesUI_SelectionChanged event go?

Nowhere. MVVM works best with a property/DataBinding based approach, as opposed to a procedural event-based approach.

For instance, a ComboBox-based UI that "does stuff" when the user changes the selection in the ComboBox should be defined like this:

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

ViewModel:

public class ViewModel
{
    public ObservableCollection<MyItems> MyCollection {get;set;}

    private void _selectedItem;
    public MyItem SelectedItem
    {
       get { return _selectedItem; }
       set
       {
           _selectedItem = value;
           NotifyPropertyChanged();

           DoStuffWhenComboIsChanged();
       }
    }

    private void DoStuffWhenComboIsChanged()
    {
       //... Do stuff here
    }
}

Now you have more assignments, more variables, more functions that just call other functions than just a simple MyTitlesUI.SelectedItem to deal with.

Wrong. What you have now is a Strongly Typed property in the ViewModel of type MyItem that you work with instead of the horrible casting stuff (MyItem)ComboBox.SelectedItem or things of that sort.

This approach has the additional advantage that your application logic is completely decoupled from the UI and thus you're free to do all sorts of crazy stuff on the UI (such as replacing the ComboBox for a 3D rotating pink elephant if you wanted to).

Why not bring the DBClass reference up to the View or similar?

Because DataBase code does NOT belong into the UI.

Especially if you're doing a lot of UI manipulation

You don't do "UI manipulation" in WPF. You do DataBinding which is a much cleaner and scalable approach.

Upvotes: 4

Related Questions