Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Aug 22 01:47

    dependabot-preview[bot] on nuget

    (compare)

  • Aug 22 01:47

    dependabot-preview[bot] on develop

    Bump MethodTimer.Fody from 3.0.… Merge pull request #94 from Wil… (compare)

  • Aug 22 01:47
    dependabot-preview[bot] closed #94
  • Aug 22 01:46
    dependabot-preview[bot] synchronize #94
  • Aug 22 01:46

    dependabot-preview[bot] on nuget

    Bump MethodTimer.Fody from 3.0.… (compare)

  • Aug 22 01:46
    dependabot-preview[bot] edited #94
  • Aug 22 01:45
    dependabot-preview[bot] edited #94
  • Aug 22 01:45

    dependabot-preview[bot] on nuget

    (compare)

  • Aug 22 01:45

    dependabot-preview[bot] on develop

    Bump Obsolete.Fody from 5.0.0 t… Merge pull request #95 from Wil… (compare)

  • Aug 22 01:45
    dependabot-preview[bot] closed #95
  • Aug 22 01:44
    dependabot-preview[bot] synchronize #95
  • Aug 22 01:44

    dependabot-preview[bot] on nuget

    Bump Obsolete.Fody from 5.0.0 t… (compare)

  • Aug 22 01:44
    dependabot-preview[bot] edited #95
  • Aug 22 01:43
    dependabot-preview[bot] edited #95
  • Aug 22 00:16

    dependabot-preview[bot] on nuget

    (compare)

  • Aug 22 00:16

    dependabot-preview[bot] on develop

    Bump ModuleInit.Fody from 2.0.0… Merge pull request #93 from Wil… (compare)

  • Aug 22 00:16
    dependabot-preview[bot] closed #93
  • Aug 22 00:15
    dependabot-preview[bot] labeled #95
  • Aug 22 00:15
    dependabot-preview[bot] opened #95
  • Aug 22 00:15

    dependabot-preview[bot] on nuget

    Bump Obsolete.Fody from 5.0.0 t… (compare)

Geert van Horrik
@GeertvanHorrik
If you have any questions / ideas about Orc.ProjectManagement, feel free to post them here.
Greg Carter
@greg9504

Hello, downloaded the source and compiled/ran the sample, think there is a bug in the example Save As:
line 159 of MainWindowViewModel.cs
await _projectManager.SaveAsync(_openFileService.FileName).ConfigureAwait(false);
should be:
await _projectManager.SaveAsync(_saveFileService.FileName).ConfigureAwait(false);

There seems to be some other problems, either with the projectManager or with the example. After changing the line above, if I modify the "saved as" file outside of the example, I don't get a refresh message box and the displayed data doesn't update. If I then hit the Refresh button, the contents update. If I then modify the file outside the app, I get TWO messages informing me that the project has changed.

Geert van Horrik
@GeertvanHorrik
@greg9504 Thanks for letting us know, I think you are right. We will look into this.
Geert van Horrik
@GeertvanHorrik
@greg9504 see WildGums/Orc.ProjectManagement#2 for further details
Greg Carter
@greg9504
I've updated the ticket with some additional info and how I have it working now.
Greg Carter
@greg9504

I've updated the sample a bit: added a close button, on start up or close of a file opens a "temp" file for the current project (Save disabled, SaveAs enabled), once you SaveAs the Save becomes enabled. Just to flush out the sample so it behaves how you would expect a Project would. I'm still new to Catel and wouldn't mind your comments on the changes. However I understand you are busy with Catel 4.5 release...

This is what I did:
Add a property to MainWindowViewModel to keep track of whether it is a temp file or a loaded file:

public bool IsTempFile { get; private set; }

Which is initialized to false in constructor
In MainWindowViewModel.InitializeAsync add check for null Project and create a temp file to hold a "new" project:

 protected override async Task InitializeAsync()
        {
            await base.InitializeAsync().ConfigureAwait(false);

            _projectManager.ProjectActivatedAsync += OnProjectActivatedAsync;
             ReloadProject();
            if (Project == null)
            {
                CreateEmptyProject();
            }

        }

In MainWindowViewModel.OnLoadProjectExecuteAsync check to see if Project loaded and set IsTempFile to false if it has:

private async Task OnLoadProjectExecuteAsync()
        {
            _openFileService.InitialDirectory = Path.Combine(Environment.CurrentDirectory, "Data");
            _openFileService.Filter = TextFilter;

            if (_openFileService.DetermineFile())
            {
                await _projectManager.LoadAsync(_openFileService.FileName).ConfigureAwait(false);
                if (Project != null && Project.Location != null && string.Compare(Project.Location,_openFileService.FileName) == 0)
                {
                    //load ok
                    IsTempFile = false;
                }
            }
        }

In MainWindowViewModel.OnSaveProjectCanExecute add check for IsTempFile to force SaveAs

private bool OnSaveProjectCanExecute()
        {
            return _projectManager.ActiveProject != null && !IsTempFile;
        }

In MainWindowViewModel.OnSaveProjectAsExecuteAsync set IsTempFile to false

 private async Task OnSaveProjectAsExecuteAsync()
        {
            _saveFileService.Filter = TextFilter;
            if (_saveFileService.DetermineFile())
            {
                //await _projectManager.SaveAsync(_openFileService.FileName).ConfigureAwait(false);
                await _projectManager.SaveAsync(_saveFileService.FileName).ConfigureAwait(false);                
                IsTempFile = false;
            }
        }

In MainWindowViewModel.OnCloseProjectExecuteAsync make call to Create empty project:

private async Task OnCloseProjectExecuteAsync()
        {
            await _projectManager.CloseAsync();
            CreateEmptyProject();
        }

private void CreateEmptyProject()
        {
            string location = PersonProject.CreateEmptyProject();
            _projectManager.LoadAsync(location).ConfigureAwait(false);
            IsTempFile = true;
        }

and static method to PersonProject

public static string CreateEmptyProject()
        {
            try
            {
                string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".txt";
                using (File.Create(fileName)) { }//creates empty file
                //fill your project with defaults here if needed
                return fileName;

            }
            catch
            {

            }
            return null;
        }

and update the reader to handle empty file in PersonProjectReader.ReadFromLocationAsync line 25

var content = textReader.ReadLine();
                        if (content == null)
                        {
                            return project;
                        }
Geert van Horrik
@GeertvanHorrik
Looks good. Interested in doing this as a PR?
Greg Carter
@greg9504
sure.
Greg Carter
@greg9504

Hi, I'm having a problem implementing a db backed project. I'm missing something conceptually I think. I would value your thoughts on my approach. My problem revolves around UnitOfWork. Basically I want to have the UnitOfWork live until the project is saved (so openproject = begin transaction, saveproject=commit).

I have a simple db (sqlite) with a few tables, lets call them Departments and Employees that makes up my project. My DAL consists of (FWIW it was generated using http://blog.gauffin.org/2016/02/05/griffin-dal-generator-take-2/ ):

    public interface IDepartmentRepository
    {
        void Create( Department entity);
        void Delete(int id)
        void Delete( Department entity)
        void Update( Department entity)
    }
    public class Department : ModelBase
    {
        public int Id { get; set; }
        public string Name { get; set; }
       //etc...
    }
    //Maps Department to db columns
    internal class DepartmentMapper{//code omitted}
   //IRepository implementation
   public class  DepartmentRepository : IDepartmentRepository
    {       
        public  DepartmentRepository(IUnitOfWork unitOfWork)
        public void Create( Department entity);
        public void Delete(int id)
        public void Delete( Department entity)
        public void Update( Department entity)
        //etc
    }

Note the repository takes a unitofwork in the constructor. I then have ViewModels that take an IDepartmentRepository instance in their constructor. Much like Prism example in Catel.
...

In my ModuleInitializer I do:

        ServiceLocator.Default.RegisterType<IConnectionFactory, ConnectionFactory>();
        ServiceLocator.Default.RegisterType<IUnitOfWork, AdoNetUnitOfWork>();
        ServiceLocator.Default.RegisterType<IDepartmentRepository, DepartmentRepository>();

Then in the project management reader:

 protected override async Task<IProject> ReadFromLocationAsync(string location)
        {
            IDbConnection conn = _connectionFactory.Create(location);           
            //AdoNetUnitOfWork is 3rd party and constructor takes a bool to indicate that the connection is owned
           //by the UnitOfWork.  I needed to set this to true, so when the unit of work is disposed the connection
           //object associated with it is disposed.  So I couldn't find a way to have it created by dependency injection
           //and instead had to use the TypeFactory CreateInstance followed by RegisterInstance.
            IUnitOfWork uow = TypeFactory.Default.CreateInstanceWithParametersAndAutoCompletion<AdoNetUnitOfWork>(conn, true);
            ServiceLocator.Default.RegisterInstance<IUnitOfWork>(uow);
            var tProject = new TAnalyzeProjectModel(location);
            tProject.UnitOfWork = uow;//this may not be needed as we can Resolve the current instance in the writer.
      }

In the project writer:

protected override Task<bool> WriteToLocationAsync(TAnalyzeProjectModel project, string location)
        {
            IUnitOfWork uow = ServiceLocator.Default.ResolveType<IUnitOfWork>();

            if (!string.Equals(project.Location,location))
            {
                //SaveAs, create a new empty db then copy contents of currently open db to it,
                //then close current db to discard any changes
                LogTo.Debug("Performing SaveAs...");
               //ignore SaveAs for now
                return TaskHelper<bool>.FromResult(true);
            }
            //project.UnitOfWork.SaveChanges();
            uow.SaveChanges();
           //new a new UnitOfWork to start new transaction to db.
           //open new connection to db
            IDbConnection conn = _connectionFactory.Create(location);                       
            IUnitOfWork newuow = TypeFactory.Default.CreateInstanceWithParametersAndAutoCompletion<AdoNetUnitOfWork>(conn, true);
            ServiceLocator.Default.RegisterInstance<IUnitOfWork>(uow);
            return TaskHelper<bool>.FromResult(true);
       }

So after a Save there may be instances of DepartmentViewModel that have a Repository object that has a UnitOfWork that is "old".

So first question:
When ServiceLocator.Default.RegisterInstance is called what happens to previous registered instances? Disposed?
Second question:
How do existing ViewModels know that the UnitOfWork has changed? Should I use the message service and have the ViewModels do something like (pseudo code):

private void OnUnitOfWorkUpdated()
{
    IUnitOfWork uow = ServiceLocator.Default.ResolveType<IUnitOfWork>();
    _departmentRepository = ServiceLocator.Default.ResolveType<IDepartmentRepository>();
}

Then in the Writer send out the message that he UnitOfWork has updated?
Will the call to ResolveType force a new instance to be created so the new UnitOfWork is picked up?

Thanks.

Geert van Horrik
@GeertvanHorrik
  1. When RegisterInstance is called, any current implementations will be overwritten. The thing is: why do you want to register a short-living object in the service locator? You could consider registering it as Transient so it will create a new instance every time you resolve it.
  1. The view models shouldn't be aware of changed types in the service locator that are being updated. (yes, there is the ServiceLocator.TypeRegistered), but I think the responsibility to respond to this shouldn't be in the view models hands.
What I recommend is 1 single service or manager that manages the unit of work. This way, you can register 1 service in the container and have it injected into all your view models. Then whenever the project is saved, a project watcher object refreshes the service and all view models can respond to this. This keeps the view models as dumb as possible and the lifetime behavior of the unit of work into 1 single location
Greg Carter
@greg9504
I'm not sure I quite follow you on how the ViewModels will pick up the change. Would this mean that instead of injecting a IDepartmentResposity into my view model I would instead inject the IUnitOfWorkSerivce. Where IUnitOfWork has a "GetCurrent" method. Then whenever I need to do an update/insert/delete in the ViewModel I create a new DepartementResposity(_uowService.GetCurrent())? How do I keep my ViewModels "dumb" with respect to the Repository then (IDepartmentRepository instead of DepartmentReposity)?
Geert van Horrik
@GeertvanHorrik
correct, your vm should have 1 way to access the unit of work, via a service. Then, depending on how you set up your repositories, I think they can be resolved from the UnitOfWork (because the unit of work is the parent of the repositories in your case I guess)?
Greg Carter
@greg9504

Yes I guess that is a way of thinking of the reporitories.... I just reread:
https://catelproject.atlassian.net/wiki/display/CTL/Using+the+repositories+and+unit+of+work
even though I'm not using EF I think this is the model you are telling me I should follow.
But in my case something like this:

using (var uow = new UnitOfWork<MyDbContext>())
{
    var customerRepository = uow.GetRepository<ICustomerRepository>();

    // all interaction with the customer repository is applied to the unit of work
}

would become:

using (var uow = _uowService.GetCurrent())
{
    var customerRepository = uow.GetRepository<ICustomerRepository>();

    // all interaction with the customer repository is applied to the unit of work
}

So I'll add some extension methods to my underlying UOW class that return instances of the repository interfaces, so my ViewModels continue to use the interfaces. Sound right?

Geert van Horrik
@GeertvanHorrik
yep, that's how I would do it
Greg Carter
@greg9504
thanks for your help!