Silverlight child windows in MVVM pattern

rrejc picture rrejc · Apr 17, 2009 · Viewed 18k times · Source

I am trying to find the right way to get the data from a ChildWindow/popup using a MVVM pattern in Silverlight (3). For example: I have a main page with a data entry form and I want to open a popup with a list of customers. When user selects a customer I want to transfer selected customer into the main page. This is what the (example) code which I am using at the moment:

Main page

public partial class MainPage : UserControl
{
    public MainPageViewModel ViewModel { get; private set; }

    public MainPage()
    {
        InitializeComponent();
        ViewModel = new MainPageViewModel();
        DataContext = ViewModel;
    }

    private void SearchCustomer_Click(object sender, RoutedEventArgs e)
    {
        ViewModel.SearchCustomer();
    }
}

public class MainPageViewModel: ViewModel
{
    private string customer;
    public string Customer
    {
        get { return customer; }
        set { customer = value; RaisePropertyChanged("Customer"); }
    }

    public void SearchCustomer()
    {
        // Called from a view
        SearchWindow searchWindow = new SearchWindow();
        searchWindow.Closed += (sender, e) =>
        {
            if ((bool)searchWindow.DialogResult)
            {
                Customer = searchWindow.ViewModel.SelectedCustomer.ToString();
            }
        };
        searchWindow.Show();
    }
}

Child window

public partial class SearchWindow : ChildWindow
{
    public SearchWindowViewModel ViewModel { get; private set; }

    public SearchWindow()
    {
        InitializeComponent();
        ViewModel = new SearchWindowViewModel();
        DataContext = ViewModel;
    }

    private void OKButton_Click(object sender, RoutedEventArgs e)
    {
        DialogResult = ViewModel.OkButtonClick();
    }

    private void CancelButton_Click(object sender, RoutedEventArgs e)
    {
        DialogResult = ViewModel.CancelButtonClick();
    }
}

public class SearchWindowViewModel: ViewModel
{
    private Customer selectedCustomer;        
    private ObservableCollection<Customer> customers;

    public ObservableCollection<Customer> Customers
    {
        get { return customers; }
        set {customers = value; RaisePropertyChanged("Customers"); }
    }

    public Customer SelectedCustomer
    {
        get { return selectedCustomer; }
        set { selectedCustomer = value; RaisePropertyChanged("SelectedCustomer"); }
    }

    public SearchWindowViewModel()
    {
        Customers = new ObservableCollection<Customer>();
        ISearchService searchService = new FakeSearchService();
        foreach (Customer customer in searchService.FindCustomers("dummy"))
            Customers.Add(customer);
    }

    public bool? OkButtonClick()
    {
        if (SelectedCustomer != null)
            return true;
        else
            return null; // show some error message before that
    }

    public bool? CancelButtonClick()
    {
        return false;
    }
}

Is this the right way or is there anything more "simple"?

Cheers, Rok

Answer

Ray Booysen picture Ray Booysen · Apr 20, 2009

More problematic here is the use of View specific terms and types in your VMs. Click events, DialogResults should not be anywhere near your ViewModels.

With regards to the question, I had a similiar question about this here: Handling Dialogs in WPF with MVVM

The answer I accepted was the use of the Mediator pattern to get around this. Have a look. :)