I need to build a processing screen for customer locations that determines and then updates the residential flag on locations.
This code correctly processes each selected record and appears to update the appropriate fields. But the problem I am encountering is that my changes to Location are not being saved back to the database.
The Customer Locations graph requires the business account to be specified before you can enter a Location ID, and I suspect that because of that I cannot simply update the Locations view on the graph. But I cannot find any documentation or code examples indicating what approach I should use here.
Here is the code on my processing screen graph:
public class ProcessCustomerLocations : PXGraph<ProcessCustomerLocations>
{
public PXCancel<Location> Cancel;
public PXProcessing<Location, Where<Location.isActive, Equal<True>>> Locations;
public static void Process(List<Location> locations)
{
var graph = PXGraph.CreateInstance<CustomerLocationMaint>();
CustomerLocationMaint_Extension graphExt = graph.GetExtension<CustomerLocationMaint_Extension>();
foreach (var location in locations)
{
graphExt.UpdateLocation(location, true);
}
}
public ProcessCustomerLocations()
{
Locations.SetProcessDelegate(Process);
}
}
And here is my code on the CustomerLocationMaint_Extension graph:
public class CustomerLocationMaint_Extension : PXGraphExtension<CustomerLocationMaint>
{
public void UpdateLocation(Location location, bool isMassProcess = false)
{
bool isRes = false;
Base.Location.Current = Base.Location.Search<Location.locationID>(location.LocationID, location.BAccountID);
LocationExt locationExt = location.GetExtension<LocationExt>();
// INSERT CODE TO DETERMINE VALUE OF isRes
locationExt.UsrResidentialValidated = true;
location.CResedential = isRes;
Base.Location.Update(location);
Base.Actions.PressSave();
}
}
One of the fields I am updating on Location is a custom field called UsrResidentialValidated. Here is the code for that field.
namespace PX.Objects.CR
{
public class LocationExt : PXCacheExtension<PX.Objects.CR.Location>
{
#region UsrResidentialValidated
[PXDBBool]
[PXUIField(DisplayName="Residential Validated")]
public virtual bool? UsrResidentialValidated { get; set; }
public abstract class usrResidentialValidated : IBqlField { }
#endregion
}
}
Update
Thanks to some help from #Samvel I've modified the UpdateLocation code as follows. The following code does save the changes to the database (both on the custom field and the non-custom field), which is great. However, in order to do that, I had to create a new Location object "myLocation" and am no longer using the "location" object that the PXProcessing graph passed to UpdateLocation. This means that after processing, when the processing screen displays the processed records with the modified data (after processing finishes and before you refresh the screen), it does not show the updated values. Is there any way to both have the processing screen show the updated values and save the changes to the database?
public void UpdateLocation(PX.Objects.CR.Location location, bool isMassProcess = false)
{
bool isRes = true;
Location myLocation = PXSelect<Location,
Where<Location.bAccountID, Equal<Required<Location.bAccountID>>, And<Location.locationID, Equal<Required<Location.locationID>>>>>
.Select(this.Base, location.BAccountID, location.LocationID);
this.Base.Location.Current = myLocation;
LocationExt locationExt = myLocation.GetExtension<LocationExt>();
locationExt.UsrResidentialValidated = true;
myLocation.CResedential = isRes;
Base.Location.Current = Base.Location.Update(myLocation);
this.Base.Save.Press();
}
UPDATED
I have updated the code to correspond to your case. After processing all the records the records in the grid are being updated and showing modified records.
You can download the customization package for this code by this link
To create a processing page for updating Location you should do the following steps:
Add "Selected" field to the Location DAC
public sealed class LocationExt: PXCacheExtension<Location>
{
#region Selected
public abstract class selected : IBqlField
{ }
[PXBool()]
[PXDefault(true,PersistingCheck = PXPersistingCheck.Nothing)]
[PXUIField(DisplayName = "Selected")]
public bool? Selected { get; set; }
#endregion
#region UsrResidentialValidated
[PXDBBool]
[PXUIField(DisplayName = "Residential Validated")]
public bool? UsrResidentialValidated { get; set; }
public abstract class usrResidentialValidated : IBqlField { }
#endregion
}
This step is required because otherwise your delegate for SetProcessDelegate will never be called.
Acumatica is checking if there is at least one selected record before calling Process Delegate.
Create the Processing Graph like below:
using PX.Data;
using PX.Objects.CR;
using System.Collections.Generic;
namespace CustomerLocationUpdate
{
public class ProcessCustomerLocations : PXGraph<ProcessCustomerLocations>
{
public PXCancel<Location> Cancel;
public PXProcessingJoin<Location,InnerJoin<BAccountR,On<Location.bAccountID,Equal<BAccountR.bAccountID>>>,
Where<Location.isActive, Equal<True>,And<Location.locType, Equal<PX.Objects.CR.LocTypeList.customerLoc>>>> Locations;
public static void Process(List<Location> locations)
{
var graph = PXGraph.CreateInstance<PX.Objects.AR.CustomerLocationMaint>();
CustomerLocationMaint_Extension graphExt = graph.GetExtension<CustomerLocationMaint_Extension>();
foreach (var location in locations)
{
graphExt.UpdateLocation(location, true);
graph.Clear();
}
}
public ProcessCustomerLocations()
{
Locations.SetProcessDelegate(Process);
}
}
}
As you can see I have implicitly specified PX.Objects.AR and PX.Objects.CR for some reason the program has worked only this way on my instance.
Create the UpdateLocation method in the GraphExtension:
using PX.Data;
namespace CustomerLocationUpdate
{
public class CustomerLocationMaint_Extension : PXGraphExtension<PX.Objects.AR.CustomerLocationMaint>
{
public void UpdateLocation(PX.Objects.CR.Location location, bool isMassProcess = false)
{
bool isRes = false;
this.Base.Location.Current = PXSelect<PX.Objects.CR.Location,Where<PX.Objects.CR.Location.bAccountID,Equal<Required<PX.Objects.CR.Location.bAccountID>>,And<PX.Objects.CR.Location.locationID,Equal<Required<PX.Objects.CR.Location.locationID>>>>>.Select(this.Base,location.BAccountID,location.LocationID);
this.Base.Location.Current.CResedential = isRes;
LocationExt locationExt = PXCache<PX.Objects.CR.Location>.GetExtension<LocationExt>(this.Base.Location.Current);
locationExt.UsrResidentialValidated = false;
this.Base.Location.Current = this.Base.Location.Update(this.Base.Location.Current);
this.Base.Save.Press();
}
}
}
As you can see I am setting the Location.Current using PXSelect and not Location.Current.Search.
For some reason Location.Current.Search is always returning null.
May be it is caused by the PXProjectionAttribute applied to it, I am not sure what is the exact reason.
Related
We have a requirement to attach custom report to email as an attachment. As per our requirement we created a process screen for this. Issue we are facing is, when we use below line of code we are getting “OBJECT REFERENCE ERROR”, can you please have a look at below sample code.
public class ProcessReports : PXGraph<ProcessReports>
{
[InjectDependency]
protected IReportLoaderService ReportLoader { get; private set; }
[InjectDependency]
protected IReportRenderer ReportRenderer { get; private set; }
public PXCancel<DACName> Cancel;
public PXProcessing<DACName, Where<DACName.DACName, Equal<OPR>>> QueueList;
public ProcessReports()
{
QueueList.SetProcessDelegate(delegate (List<DACName> list)
{
SaveFile(list, true);
});
}
public static void SaveFile(List<DACName> list, bool aIsMassProcess)
{
new KWProcessWorkCenterOpenJobReports().save(list, aIsMassProcess);
}
public virtual void save(List<DACName> list, bool aIsMassProcess)
{
//here at this point we are getting error
Report _report = ReportLoader.LoadReport("AA501108", null);
}
}
Looking at your code my inference is the object with the IReportLoaderService and IReportRenderer interface decleration never properly gets initialized with PXGraph.CreateInstance<...> before calling save method.
new KWProcessWorkCenterOpenJobReports().save(list, aIsMassProcess);
The following code snippet will generate a report from the given paramaters provided and then save the file within the Acumatica system, though it can be further emailed out as mentioned in your original prompt.
using PX.Data;
using PX.Objects.AR;
using PX.Reports;
using PX.Reports.Controls;
using PX.Reports.Data;
using PX.SM;
using System.Collections.Generic;
using MailMessage = PX.Reports.Mail.Message;
namespace StackOverflow
{
public class EmailReportProc : PXGraph<EmailReportProc>
{
#region Constructor
public EmailReportProc()
{
Documents.SetProcessDelegate(generateAcumaticaReports);
}
#endregion
#region Properties
[InjectDependency]
protected IReportLoaderService ReportLoader { get; set; }
[InjectDependency]
protected IReportDataBinder ReportDataBinder { get; set; }
#endregion
#region Views
public PXCancel<ARInvoice> Cancel;
public PXProcessing<ARInvoice, Where<ARInvoice.status, Equal<ARDocStatus.pendingEmail>>> Documents;
#endregion
#region Methods
private static void generateAcumaticaReports(List<ARInvoice> Documents)
{
//Initialize new graph instance for use within static processing method.
EmailReportProc graph = PXGraph.CreateInstance<EmailReportProc>();
foreach (ARInvoice document in Documents)
{
//Paramaters for report
Dictionary<string, string> parameters = new Dictionary<string, string>
{
{ "ARInvoice.DocType", document.DocType },
{ "ARInvoice.RefNbr", document.RefNbr }
};
//Load report - ReportID must be valid sitemap entry in system
Report report = graph.ReportLoader.LoadReport("AR622000", null);
//Initialize the parameters for the report
graph.ReportLoader.InitDefaultReportParameters(report, parameters);
ReportNode reportNode = graph.ReportDataBinder.ProcessReportDataBinding(report);
//Generate PDF Report and creates Acumatica file.
FileInfo fileInfo = new FileInfo(reportNode.ExportFileName + ".pdf", null, MailMessage.GenerateReport(reportNode, RenderType.FilterPdf)[0]);
UploadFileMaintenance uploadFileMaintenance = PXGraph.CreateInstance<UploadFileMaintenance>();
//Save Generated file into system
_ = uploadFileMaintenance.SaveFile(fileInfo);
}
}
#endregion
}
}
I'm lost and not sure I am going about this the right way.
I have placed a PXAction Button on the EP305000 screen.
EP305000 Screen
When the button is pressed I wanted to search for any records in the PMTimeActivity table for the current user that has the UsrPIXIClockIn NOT null AND the UsrPIXIClockOut Null.
If found, need to set its value to the current time. If not found then create a new record with the UsrPIXIClockIn field set to the current time.
However, my first attempt of just trying to read the Usr fields is creating an error. When I try to parse a PXResultSet, code lines containing my Usr Fields are throwing an error when compiling.
There error is: 'PX.Objects.CR.PMTimeActivity' does not contain a definition for 'UsrPIXIClockIn' and no extension method 'UsrPIXIClockIn' accepting a first argument of type 'PX.Objects.CR.PMTimeActivity'
I am not sure where this definition belongs or how to define it. Here is the Code I have:
[Serializable]
public class PMTimeActivityExt : PXCacheExtension<PMTimeActivity>
{
public PXSelect<PMTimeActivity> PMTimeActivity;
#region UsrPIXIClockIn
[PXDBTime(DisplayMask = "t", UseTimeZone = false)]
[PXUIField (DisplayName="Clock In")]
public virtual DateTime? UsrPIXIClockIn { get; set; }
public abstract class usrPIXIClockIn : IBqlField { }
#endregion
#region UsrPIXIClockOut
[PXDBTime(DisplayMask = "t", UseTimeZone = false)]
[PXUIField (DisplayName="Clock Out")]
public virtual DateTime? UsrPIXIClockOut { get; set; }
public abstract class usrPIXIClockOut : IBqlField { }
#endregion
#region UsrPIXITotalHours
[PXDBDecimal]
[PXUIField (DisplayName="Total Hours")]
public virtual decimal? UsrPIXITotalHours { get; set; }
public abstract class usrPIXITotalHours : IBqlField { }
#endregion
}
public class TimeCardMaint_Extension : PXGraphExtension<TimeCardMaint>
{
public PXSelect<PMTimeActivity> PMTimeActivity;
public PXAction<EPTimeCard> PunchCard;
public PXAction<PX.Objects.EP.EPTimeCard> PunchTimeCard;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Punch Time Card")]
protected void punchTimeCard(PXCache cache)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.AppendLine("Started...\n");
EPEmployee employeeByUserID = PXSelect<EPEmployee, Where<EPEmployee.bAccountID, Equal<Current<EPTimeCard.employeeID>>>>.Select(this.Base);
Guid userID = (Guid) employeeByUserID.UserID;
sb.AppendLine("user ID:" + userID.ToString() + "\n");
// This one returns all records.
PXResultset<PMTimeActivity> TimeActivity = PXSelect<PMTimeActivity>.Select(this.Base);
foreach (PMTimeActivity timeRecord in TimeActivity)
{
if (timeRecord.OwnerID == userID) {
sb.AppendLine("UsrPIXIClockIn:" + timeRecord.UsrPIXIClockIn + "\n");
}
}
sb.AppendLine("\nEnded...\n");
throw new PXException("Clicked Punch Time Card!\n" + sb.ToString());
}
}
As for the PXSelect for the PXResultSet I tried this:
PXResultset<PMTimeActivity> TimeActivity = PXSelect<PMTimeActivity, Where<Required<PMTimeActivity.ownerID>, Equal<Current<PMTimeActivity.ownerID>>>>.Select(this.Base, userID);
But no records are ever found. What am I doing wrong?
The error message boils down to: PMTimeActivity does not contain UsrPIXIClockIn.
PMTimeActivity is the base DAC and the user fields are in the extended DAC PMTimeActivityExt.
You need to fetch the extension from the base DAC first using GetExtension method and access your user field on the extension record timeRecordExt.UsrPIXIClockIn:
foreach (PMTimeActivity timeRecord in TimeActivity)
{
PMTimeActivityExt timeRecordExt = timeRecord.GetExtension<PMTimeActivityExt>();
if (timeRecordExt != null && timeRecord.OwnerID == userID) {
sb.AppendLine("UsrPIXIClockIn:" + timeRecordExt.UsrPIXIClockIn + "\n");
}
}
In your question I see there's a data view declaration in the DAC extension. Maybe that's a typo, you should remove it as DAC extension should only contain user fields. This is important because Acumatica aggressively parses these code structures. So remove that line from PMTimeActivityExt class:
public PXSelect<PMTimeActivity> PMTimeActivity;
We have a custom processing screen that is updating a custom field called UsrDateNotified in the ARTran table where the UsrDateNotified is prior to the RevisionDateReceived in a custom table ItemBaseDocument. We also need to update the UsrDateNotified field in table ItemBaseDocument which is linked to the InventoryID in ARTran. Our current code below validates for updating the ARTran table, but we are struggling with how to also update the related ItemBaseDocument for the selected ARTran records. What is the right approach for this scenario?
using System;
using System.Collections;
using System.Linq;
using PX.Data;
using PX.SM;
using PX.Objects.AR;
using PX.Objects.CR;
using PX.Objects.IN;
namespace DocCenter
{
public class UpdateLastNotified : PXGraph<UpdateLastNotified>
{
public PXFilter<UpdateLastNotifiedFilter> MasterView;
public PXCancel<UpdateLastNotifiedFilter> Cancel;
[PXFilterable]
public PXSelect<ARTran> DetailsView;
public UpdateLastNotified()
{
Cancel.SetCaption("Clear Filter");
this.DetailsView.Cache.AllowInsert = false;
this.DetailsView.Cache.AllowDelete = false;
this.DetailsView.Cache.AllowUpdate = true;
}
protected virtual IEnumerable detailsView()
{
UpdateLastNotifiedFilter filter = MasterView.Current as UpdateLastNotifiedFilter;
PXSelectBase<ARTran> cmd = new PXSelectJoinOrderBy<ARTran,
InnerJoin<InventoryItem, On<ARTran.inventoryID, Equal <InventoryItem.inventoryID>>,
InnerJoin<ItemBaseDocument, On<InventoryItemExt.usrDocumentNumber, Equal<ItemBaseDocument.baseDocumentCode>>,
InnerJoin<Contact, On<ARTranExt.usrContactID, Equal<Contact.contactID>>>>>,
OrderBy<Asc<ARTran.tranDate>>>(this);
cmd.WhereAnd<Where<ContactExt.usrNotificationPriority,
Equal<Current<UpdateLastNotifiedFilter.notificationPriority>>>>();
cmd.WhereAnd<Where<ARTranExt.usrDateNotified,
Less<ItemBaseDocument.revisionDateReceived>>>();
if (filter.BaseDocumentCode != null)
{
cmd.WhereAnd<Where<InventoryItemExt.usrDocumentNumber,
Equal<Current<UpdateLastNotifiedFilter.baseDocumentCode>>>>();
}
return cmd.Select();
}
public PXAction<UpdateLastNotifiedFilter> Process;
[PXProcessButton]
[PXButton(CommitChanges=true)]
[PXUIField(DisplayName = "Process")]
protected virtual IEnumerable process(PXAdapter adapter)
{
PXLongOperation.StartOperation(this, delegate()
{
foreach(ARTran tran in DetailsView.Select())
{
if (tran.Selected==true)
{
ARTranExt tranExt = tran.GetExtension<ARTranExt>();
ARInvoiceEntry tranEntry = new ARInvoiceEntry();
tranExt.UsrDateNotified = MasterView.Current.DateNotified;
tranEntry.Transactions.Update(tran);
tranEntry.Save.PressButton();
}
}
}
);
return adapter.Get();
}
[Serializable]
public class UpdateLastNotifiedFilter : IBqlTable
{
public static class NotificationPriority
{
public const string None = "N";
public const string Alert = "A";
public const string Express = "E";
public const string Shipment = "P";
public const string Subscription = "S";
}
#region NotificationPriority
public abstract class notificationPriority : PX.Data.IBqlField
{
}
[PXDBString(1, IsFixed = true)]
[PXDefault(NotificationPriority.None)]
[PXUIField(DisplayName = "Notification Type")]
[PXStringList(
new string[]
{
NotificationPriority.None,
NotificationPriority.Alert,
NotificationPriority.Express,
NotificationPriority.Shipment,
NotificationPriority.Subscription
},
new string[]
{
"None",
"Alert",
"Express",
"Shipment",
"Subscription"
})]
#endregion
#region BaseDocumentID
public abstract class baseDocumentCode : PX.Data.IBqlField
{
}
[PXString(50)]
[PXUIField(DisplayName="Document Number")]
[PXSelector(typeof(DocCenter.ItemBaseDocument.baseDocumentCode))]
public virtual String BaseDocumentCode
{
get;
set;
}
#endregion
#region DateNotified
public abstract class dateNotified : PX.Data.IBqlField
{
}
[PXDBDate()]
[PXDefault(typeof(AccessInfo.businessDate))]
[PXUIField(DisplayName = "Date Notified")]
public DateTime? DateNotified { get; set; }
#endregion
}
}
}
Your best bet would be to create a view that selects ItemBaseDocument.
PXSelect<ItemBaseDocument> ViewName;
In your for loop of your action button, you will want to create a new ItemBaseDocument object and set it equal to the corresponding ItemBaseDocument row entry. You can then update the date of this object, and when you execute your Save.PressButton() action, that should save the updates to that entry as well.
foreach(ARTran tran in DetailsView.Select())
{
if (tran.Selected==true)
{
ARTranExt tranExt = tran.GetExtension<ARTranExt>();
ARInvoiceEntry tranEntry = new ARInvoiceEntry();
tranExt.UsrDateNotified = MasterView.Current.DateNotified;
tranEntry.Transactions.Update(tran);
tranEntry.Save.PressButton();
//Target Added Code
ItemBaseDocument doc = PXSelect<ItemBaseDocument, Where<ItemBaseDocument.inventoryID,
Equal<Required<ARTran.inventoryID>>>>.Select(tran.InventoryID);
doc.UsrDateNotified = MasterView.Current.DateNotified;
}
}
Disclaimer: There may be a syntax error in the added code above. If there is, please let me know and I will fix it.
I have been trying to add custom DAC record which is the in database. But it is now working. Here is how I have tried to accomplish.
public class SquarePOSTransactionInquiry : PXGraph<SquarePOSTransactionInquiry>
{
public PXSave<MasterTable> Save;
public PXCancel<MasterTable> Cancel;
public PXFilter<MasterTable> MasterView;
public PXSelect<INSquarePOSTransaction> INSquarePOSTransactions;
public PXAction<MasterTable> calc;
[PXUIField(DisplayName = "Sync Square Transactions")]
[PXProcessButton()]
protected virtual IEnumerable Calc(PXAdapter adapter)
{
PXLongOperation.StartOperation(this, () =>
{
using (var scope = new PXTransactionScope())
{
INSquarePOSTransaction trans = new INSquarePOSTransaction();
trans.TransacationCD = "new";
trans.Description = "Another new";
var test = this.INSquarePOSTransactions.Insert(trans);
this.INSquarePOSTransactions.Cache.IsDirty = true;
//this.INSquarePOSTransactions.Update(trans);
this.Actions.PressSave();
scope.Complete();
}
});
return adapter.Get();
}
public SquarePOSTransactionInquiry()
{
}
[Serializable]
public class MasterTable : IBqlTable
{
}
}
I tried setting cache IsDirty property to false, but that didn't help too. But the strange part is updating the DAC is working. I have even looked into other Business Logic codes from other pages and it looks same like I have tried above. Could you please tell me what I am missing?
Thanks.
Within the method that you pass to StartOperation(),
you have to create a new instance of the graph and invoke the processing method on that instance.
I have small WPF application. There are 5 projects in solution.
I want separate DOMAIN classes with UI ENTITIES and I want to use AUTOMAPPER.
You can download whole solution here: TestWPFAutomapper.zip
Domain class(Domain.Source.cs) with UI Entity(Entities.Destination.cs) have same signature.
In Entities.Destination.cs I would like to put other logic.
namespace DOMAIN
{
public class Source
{
public int Id { get; set; }
public int Position { get; set; }
}
}
using System.ComponentModel;
namespace ENITITIES
{
public class Destination : INotifyPropertyChanged
{
private int _id;
private int _position;
public int Id
{
get { return _id; }
set
{
_id = value;
OnPropertyChanged("Id");
}
}
public int Position
{
get { return _position; }
set
{
_position = value;
OnPropertyChanged("Position");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
My data comes from DAL.DataContext using Entity Framework with CodeFirst. Here I´m using Source class.
using System.Data.Entity;
using DOMAIN;
namespace DAL
{
public class DataContext : DbContext
{
public DbSet<Source> Sources { get; set; }
}
}
Mapping is in BL.MyAppLogic.cs . In this class I have property Items which is ObservableCollection.
After puting another item into DB for Source class collection get refresh but for Destination is not refreshing.
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Linq;
using AutoMapper;
using DAL;
using DOMAIN;
using ENITITIES;
namespace BL
{
public class MyAppLogic
{
private readonly DataContext _dataContext = new DataContext();
public ObservableCollection<Source> Items { get; set; }
//public ObservableCollection<Destination> Items { get; set; }
public MyAppLogic()
{
Database.SetInitializer(new MyInitializer());
Mapping();
_dataContext.Sources.Load();
Items = _dataContext.Sources.Local;
//Items = Mapper.Map<ObservableCollection<Source>, ObservableCollection<Destination>>(_dataContext.Sources.Local);
}
private void Mapping()
{
Mapper.CreateMap<Source, Destination>().ReverseMap();
// I tried also Mapper.CreateMap<ObservableCollection<Source>, ObservableCollection<Destination>>().ReverseMap();
}
public int GetLastItem()
{
return _dataContext.Database.SqlQuery<int>("select Position from Sources").ToList().LastOrDefault();
}
public void AddNewItem(Destination newItem)
{
_dataContext.Sources.Add(Mapper.Map<Destination, Source>(newItem));
_dataContext.SaveChanges();
}
}
}
My problem is not with mapping, that’s works good, but with refreshing collection after adding or removing items from db. If I use DOMAIN.Source class everything works, collection is refreshing. But when I’m using ENTITIES.Destination data comes from DB and also I can put som new data to DB but refresing ObservableCollection is not working.
Please try to comment lines(14 & 23) in BL.MyAppLogic.cs and uncomment(15 & 24) and you’ll see what I mean.
Thank you for any help.
I got it but I don´t know if is correct.
Local has CollectionChanged event
so in constructor I put these lines
public MyAppLogic()
{
Database.SetInitializer(new MyInitializer());
Mapping();
_dataContext.Sources.Load();
_dataContext.Sources.Local.CollectionChanged += SourcesCollectionChanged;
Items = Mapper.Map<ObservableCollection<Source>, ObservableCollection<Destination>>(_dataContext.Sources.Local);
}
and handler looks
private void SourcesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
var source = sender as ObservableCollection<Source>;
Mapper.Map(source, Items);
}
Now is my collection automating refreshing when I put something to DB in my UI.
Looks like automapper don´t put reference into Items, but create new instance.