I suspect there is a term for this behavior that, if I knew it, I could google it and learn what I need. However, I don't know it.
Here is my constructor:
[Export(typeof(MainWindowViewModel))]
public class MainWindowViewModel : ObservableObject
{
private readonly IProductService _productService;
private readonly IProfileService _profileService;
public IEnumerable<ProductViewModel> Products { get; private set; }
private ProductViewModel _productSelected;
[ImportingConstructor]
public MainWindowViewModel(IProductService productService, IProfileService profileService, ILoggingService logger)
{
Products = _productService.InstalledProducts.Select(p => new ProductViewModel(p, _profileService, _logger));
SelectTheProductInDirectoryRunningFrom();
_productSelected.Load();
}
protected virtual void SelectTheProductInDirectoryRunningFrom()
{
string currentDir = Directory.GetCurrentDirectory();
if (_productSelected != null && _productSelected.InstalledPath != null &&
!_productSelected.InstalledPath.Contains(currentDir))
{
_productSelected =
Products.Where(p => currentDir.Contains(p.InstalledPath)).Select(p => p).DefaultIfEmpty(
_productSelected).SingleOrDefault();
}
}
It seems pretty self-explanatory. It builds a collection of ProductViewModel
s, finds the relevant one, and calls Load()
on it. ProductViewModel.Load()
contains this code:
public class ProductViewModel : ObservableObject
{
private readonly IProfileService _profileService;
private readonly ILoggingService _logger;
private ObservableCollection<ProfileViewModel> _profiles;
private ConfigProfile _defaultConfig;
private ProfileViewModel _currentProfile;
public ListCollectionView Profiles { get; set; }
public bool Load(string errorMessage, bool critical)
{
List<ProfileViewModel> profileVms = new List<ProfileViewModel> { _currentProfile };
profileVms.AddRange(
_profileService.GetSavedProfiles(_data.ProductType).Select(
p =>
{
p.FilePath = current.FilePath;
return new ProfileViewModel(p, _defaultConfig, _profileService) { IsChanged = false };
}));
_profiles = new ObservableCollection<ProfileViewModel>(profileVms);
Profiles = new ListCollectionView(_profiles);
Profiles.SortDescriptions.Add(new SortDescription("ProfileTypeValue", ListSortDirection.Ascending));
Profiles.SortDescriptions.Add(new SortDescription("ProfileName", ListSortDirection.Ascending));
Profiles.CurrentChanged += (sender, args) =>
{
((ProfileViewModel)Profiles.CurrentItem).Initialize();
_currentProfile = Profiles.CurrentItem as ProfileViewModel;
};
return true;
}
When I step through this code in the visual studio debugger, everything executes and both _profiles
and Profiles
are assigned to correctly. However, when execution returns from the MainWindowViewModel
constructor, _profiles
and Profiles
are both null.
I press F11 twice to arrive here:
What could be going wrong? Are my objects somehow passing out of scope? I thought maybe it had something to do with value vs reference but I can't find anything. Thanks!
Assigning to an object from a WhereSelectEnumerableIterator
creates a new object so the original list wasn't being updated.
_productSelected =
Products.Where(p => currentDir.Contains(p.InstalledPath)).Select(p => p).DefaultIfEmpty(
_productSelected).SingleOrDefault();
I added a .ToList()
onto this call
Products = _productService.InstalledProducts.Select(p => new ProductViewModel(p, _profileService, _logger));
to force the IEnumerable
into a List
which does not create a new object and does update the existing one. Thanks @Igor.