2

When opening a client file, i need the clientId that was selected to indicate which record should be queryed. I'm trying to expose the ViewModel as a static resource on the page so that it can be easily accessible by the binding.

Reason for Binding to a static resource can be found through this link. http://www.telerik.com/help/silverlight/gridview-troubleshooting-blank-cells.html

// Open an individual record when double-clicked.
public void Open()
{
    if (SelectedItem != null)
    {
        var vm = new LoanViewModel(Events);
        vm.ById(SelectedItem.Id);
        Events.PublishOnUIThread(new ShowTabEvent(vm));
    }
    this.OnPropertyChanged("Items");
}

LoanViewModel.cs

public LoanViewModel()
{ .... Query needs LoanId}

public void ById(int id)
{}

More info is from this linked Question Having my Viewmodel appear in namespace dropdown

Community
  • 1
  • 1
Master
  • 2,038
  • 2
  • 27
  • 77
  • This is an excellent example of a good follow-up question. Thank you for not making the old one a chameleon question. One suggestion (even though its pretty obvious what you want): include your current XAML and what you *want* it to look like (even if you don't know the syntax yet). – BradleyDotNET Nov 25 '14 at 21:48
  • On a side note; I'm having trouble determining what exactly is wrong with what you have. I understand *basically* what you want to do; but not where you are having trouble. – BradleyDotNET Nov 25 '14 at 21:51
  • Thank you @BradleyDotNET So when my tab is open through LoanViewModel() I get many null references because the loanID has not been established. Which is why I need the loanID. – Master Nov 25 '14 at 21:53
  • Why can't you pass it on the constructor? – BradleyDotNET Nov 25 '14 at 21:54
  • The sequence of operation at the moment is ById then LoanViewModel. Is there a way to set a "Super int Variable" such that when LoanViewModel() it can call it? I tried to simply set public int LoanId {get; set;} and within ById it sets the value, but that didn't quite work. LoanId would still be empty when LoanViewModel() is triggered. I can't pass it on the constructor because I dont have the loanID on the xaml side of the application. – Master Nov 25 '14 at 21:55
  • But in the code above, you are constructing the VM *outside* of the XAML (and you could probably make even that work). You can always have a global object that maintains state between forms; its not the most elegant solution, but it works (and with enough effort, *can* be elegant). – BradleyDotNET Nov 25 '14 at 21:59

1 Answers1

0

First, you shouldn't do a query operation within the ViewModels constructor. You shouldn't do any "expensive" operation within the constructor of a class.

Second, ViewModels shouldn't be aware of other ViewModels. So you shouldn't instantiate a ViewModel within another ViewModel.

I would suggest a different approach. Instead of trying to pass an ID to the ViewModel directly, do it via an event aggregator. Event Aggregator is basically a messaging system to send messages in a decoupled way between ViewModels.

One ViewModel register to a certain event, the other ViewModel sends it's event without know if there is any subscriber to this event or who this subscriber may be. For example the PRISM IEventAggregator.

You obtain an instance of the EventAgregator of your choice within your ViewModel (either by Dependency Injection or via Service Locator) and register your event in the constructor

public class LoanViewModel 
{
    public LoanViewModel()
    {
        IEventAggregator events = ... ; // get via ServiceLocator or via Constructor for DI
        events.GetEvent<CustomerLoadedEvent>().Subscribe(OnCustomerLoaded);
    }

    private void OnCustomerLoaded(Customer customer) 
    {
        int customerId = customer.ID;

        // do your query now
    }
}

public class OtherViewModel 
{
    IEventAggregator events;

    public LoanViewModel()
    {
        this.events; = ... ; // get via ServiceLocator or via Constructor for DI
    }

    // Should be ICommand for WPF binding...assuming SelectedItem is from type Customer
    public void Open() 
    {
        if (SelectedItem != null)
        {
            events.GetEvent<CustomerLoadedEvent>().Publish(SelectedItem);
        }
        this.OnPropertyChanged("Items");
    }
}

This way your ViewModels are completely decoupled from each other.

Of course PRISM/CompositeFramework may be a bit overkill for what you need. You can use other, simpler Event Aggregators or make your own one. Api may be different, the idea is the same

Tseng
  • 61,549
  • 15
  • 193
  • 205
  • I do like your approach, the only issue is that it's one Viewmodel. Not two seperate. Not sure if it'll have the same effect/. – Master Nov 26 '14 at 14:41