IResultWapper - help with example

Jul 11, 2011 at 4:27 PM

Hi,
I've not found any help or an example of the usage of IResultWrapper and wonder if you could help me out.

I'd like a Customer Repository to return an IResult instead of a INotifyCompleted. I assume this is the typically useage for IResultWrapper.

I've got as far as this in the Customer Repository

        public void FindCustomerByID(int ID,  Action<Customer> userCallback)
        {  
            IResultWrapper x = new IResultWrapper(() =>
            {
                var q = Manager.Customers.Where(c => c.CustomerID == ID);
                var op = q.ExecuteAsync();
                return op;
            });

            x.Execute(null);
            x.Completed += (s, e) =>
            {
                //Here does not have the results. Really need a op.Results from somewhere?
            };
        }

 

thanks

John

Coordinator
Jul 12, 2011 at 5:44 AM


IResultWrapper is a recent addition to the framework and I haven't gotten around to documenting it. It is not meant to be used in a repository, but rather in a view model as part of an action. Repository methods such as yours should follow the following signature and return an INotifyCompleted.

        public INotifyCompleted GetCustomers(string orderByPropertyName, Action<IEnumerable<Customer>> onSuccess = nullAction<Exception> onFail = null)
        {
            IEntityQuery<Customer> query = Manager.Customers;
            if (orderByPropertyName != null)
            {
                var selector = new PropertySortSelector(typeof(Customer), orderByPropertyName);
                query = query.OrderBySelector(selector);
            }
 
            EntityQueryOperation<Customer> op = query.ExecuteAsync();
            return op.OnComplete(onSuccess, onFail);
        }

Here's an example for how to use the IResultWrapper in a view model action. Sorry, I didn't have a simpler example handy. I cut out the pieces that are not relevant.

[Export]
public class StarterViewModel : Conductor<object>
{
    private readonly IAuthenticationService _authenticationService;
    private readonly ExportFactory<LoginViewModel> _loginViewModelFactory;
 
    [ImportingConstructor]
    public StarterViewModel(IAuthenticationService authenticationService, ExportFactory<LoginViewModel> loginViewModelFactory)
    {
        _authenticationService = authenticationService;
        _loginViewModelFactory = loginViewModelFactory;
    }
 
    public IEnumerable<IResult> Login()
    {
        LoginViewModel vm = _loginViewModelFactory.CreateExport().Value;
        yield return vm;
 
        yield return
            new IResultWrapper(() => _authenticationService.LoginAsync(
                new LoginCredential(vm.Username, vm.Password, null), nullnull));
    }
}
[Export]
public class LoginViewModel : ScreenIResult
{
    private readonly IWindowManager _windowManager;
    private string _password;
 
    private string _username;
 
    [ImportingConstructor]
    public LoginViewModel(IWindowManager windowManager)
    {
        _windowManager = windowManager;
#if DEBUG
        Username = "Test";
        Password = "test";
#endif
        // ReSharper disable DoNotCallOverridableMethodsInConstructor
        DisplayName = "Login";
        // ReSharper restore DoNotCallOverridableMethodsInConstructor
    }
 
    public string Username
    {
        get { return _username; }
        set
        {
            _username = value;
            NotifyOfPropertyChange(() => Username);
            NotifyOfPropertyChange(() => CanOk);
        }
    }
 
    public string Password
    {
        get { return _password; }
        set
        {
            _password = value;
            NotifyOfPropertyChange(() => Password);
            NotifyOfPropertyChange(() => CanOk);
        }
    }
 
    public bool CanOk
    {
        get { return !String.IsNullOrWhiteSpace(Username) && !String.IsNullOrWhiteSpace(Password); }
    }
 
    #region IResult Members
 
    public void Execute(ActionExecutionContext context)
    {
        _windowManager.ShowDialog(this);
    }
 
    public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
 
    #endregion
 
    public void Ok()
    {
        OnCompleted(false);
    }
 
    public void Cancel()
    {
        OnCompleted(true);
    }
 
    private void OnCompleted(bool cancel)
    {
        var args = new ResultCompletionEventArgs { WasCancelled = cancel };
        TryClose();
        Completed(this, args);
    }
}
Jul 12, 2011 at 11:11 AM

Many thanks, Marcel.. Example helps a lot!

I did notice your examples for Respositories returned an INotifyCompleted but that introduces a dependancy on IdeaBlade.
It had occured to me that if one was adding a Repository, why not hide IdeaBlade within it, leaving the ViewModel unaware of the Model's implementation.

Any particular reason why you chose to return INotifyCompleted in your framework?

thanks

John

Coordinator
Jul 13, 2011 at 10:07 PM

You have a dependency on DevForce anyway unless you don't return raw entities from the repositories, but then you leave all the rich features of the DevForce entities such as change tracking, property change notification, validation etc. on the table and have to reimplement it all by hand somewhere else. If you use IResult in your repository, you introduce a dependency to your UI framework in the data layer, which makes it hard to reuse the data layer with a different UI framework and you introduce a higher level dependency into a lower level component. You are going backwards in the dependency stack, which is generally frowned upon. DevForce is lower in the application stack.

Jul 13, 2011 at 11:52 PM

Ok, you're right. Having CM in the data layer is clearly undesirable.
(But as an aside, I wonder if the CoRoutine stuff can be split out as a separate library. Not that I am)

thanks
John

Coordinator
Jul 14, 2011 at 12:05 AM
It could. DevForce offers coroutines as well.

Sent from my iPhone

On Jul 13, 2011, at 5:59 PM, "jradxl" <notifications@codeplex.com> wrote:

From: jradxl

Ok, you're right. Having CM in the data layer is clearly undesirable.
(But as an aside, I wonder if the CoRoutine stuff can be split out as a separate library. Not that I am)

thanks
John