I am working on my first WPF project using MVVM. I have successfully managed to abstract away my service layer so that I could use (for instance) XML files to store the data. Using IEnumerable collections of my POCO's, any changes to the table on the GUI automaticaly propagated to repository.
Now I'm trying to switch over to using our company DB2 database instead. We use MyGeneration dOOdads to generate DAL's and BLL's for our DB2 database. The DAL's have built-in CRUD and other utility methods.
One of my colleagues has managed to successfully bind the MyGeneration BLL DataView to his WPF application (he did not use MVVM) so that it too could make real-time changes to the DataView (only requiring a call to the BLL's SaveChanges method).
My problem is that in the translation between the MyGeneration DataView, and my collection of POCO's, I would need to explicitly update any changes at this layer.
Am I approaching this the wrong way? Would something like AutoMapper be an answer to my problem, or would I still not have real-time mapping?
public override IEnumerable<PromotionPlanHeader> ReadAll()
{
foreach (DataRow row in bll_PROMPLANH.DefaultView.Table.Rows)
{
yield return new PromotionPlanHeader
{
PlanNumber = Convert.ToInt32(row["PLANNUMBER"]),
Active = (row["ACTIVE"].ToString() == "1"),
Capturer = row["CAPTURER"].ToString(),
Region = row["REGION"].ToString(),
Cycle = row["CYCLE"].ToString(),
Channel = row["CHANNEL"].ToString(),
StartDate = ConvertDb2Date(row["STARTDATE"].ToString()),
EndDate = ConvertDb2Date(row["ENDDATE"].ToString()),
AdvertStartDate = ConvertDb2Date(row["ADVERTSTARTDATE"].ToString()),
AdvertEndDate = ConvertDb2Date(row["ADVERTENDDATE"].ToString()),
BpcsDealNumber = Convert.ToInt32(row["BPCSDEALNUMBER"]),
Description = row["DESCRIPTION"].ToString(),
DeactivationReason = row["DEACTIVATIONREASON"].ToString(),
LastSavedUsername = row["LASTUSER"].ToString(),
LastSavedDateTime = ConvertDb2DateTime(row["LASTDATE"].ToString(), row["LASTDATE"].ToString().PadLeft(6, '0'))
};
}
}
The "WPF DataGrid Practical Examples" walkthrough has really cleared up some things for me. Particularly, the Binding in a Layered Application chapter, which demonstrates how you handle Updates and Inserts with an IEditableObject interface.
Although that makes me wonder if a BindingList is not better(?)
Related
TL;DR: How do I combine info from two database tables into a Vaadin Treetable (or, when Vaadin 7.5 is released, a heirarchical Grid)?
I have a Java Swing desktop application that does this currently, albeit probably very ineffeciently with ArrayLists of Java Beans that updates from the SQL Server every 30 seconds. Well, I'm now attempting to port this desktop app over to a Vaadin web app. The desktop app has login capabilities and I'll eventually worry about doing the same for the web app, but for now, I just want to try and get the most basic part of this web app working: The Treetable. Or, hopefully soon, a heirarchical Grid.
To help illustrate what I'm aiming for, I'll try and post an image I created that should show how the data from the two tables needs to merge into the treetable (using a partial screenshot of my existing desktop app):
I am well aware of how to use the JOIN command in SQL and I've briefly read about Referencing Another SQLContainer, but I'm still in the early stages of learning Vaadin and still trying to wrap my head around SQLContainer, FreeformQuery, and how I need to implement FreeformStatementDelegate for my project. Not to mention that I'll need to implement checkboxes for each row, as you can see in that photo, so that it updates the database when they are clicked. And a semi-checked state for the checkbox would be necessary for Jobs that have more than one OrderDetail item wherein only some of those OrderDetail items are completed. To get that working for my Java Swing program, I had to lean on an expert Java developer who already had most of the code ready, and boy, is it super-complicated!
If anyone can give me a high-level view of how to accomplish this task along with some examples, I would be indebted. I totally understand that I'm asking for a great deal here, and I'm willing to take it slow, step-by-step, as long as you are. I really want to fully understand this so I'm not just copy-pasting code without thinking.
I have never used SQLContainer so this might not be the answer you want. I just had a quick look at SQLContainer and I'm not sure if it will serve your purpose. For a TreeTable you will need a Container Implementing the Container.Hierarchical interface or the table will put a wrapper around it and you have to set the parent-children relations manually. You probably could extend SQLContainer and implement the methods from Container.Hierarchical in that class but this might get complicated.
In your situation I think I'd go with implementing my own Container, probably extending AbstractContainer, to get the listener code for free, and implementing Hierarchical. There are quite some methods to implement, I know, and so this will need some time, but most methods are quickly implemented and you can start with the basic methods and add more interfaces (Ordered, Sortable, Indexed, Filterable, Collapsible,...) later.
If done properly you'll end up with with easy readable code that can be extended in the future without to much trouble and you will not depend on future versions of SQLContainer.
Another good thing is that you'll learn a lot about the data structures (Container, Item, Property) used in vaadin. But as I said I don't really know SQLContainer so maybe there will be a better answer telling you that it is easy with the SQLContainer
For the Checkbox feature you could go display the name/product property as a CheckBox. With Icon and Caption it looks almost like you want it. See http://demo.vaadin.com/sampler/#ui/data-input/other/check-box and set an Icon. The semi-checked state could be done with css.
Hope this helps you finding the right solution for your task.
I'll admit that I'm a beginner with vaadin myself and there may be much better ways of doing this, but here's something I've mocked up which seems to work. It doesn't do everything you need but it might be a base to start from. Most importantly, for changes to be saved back into the database you'll need to update the SQLContainers when something in the container is changed.
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.HierarchicalContainer;
import com.vaadin.data.util.sqlcontainer.SQLContainer;
#SuppressWarnings("serial")
public class TwoTableHierarchicalContainer extends HierarchicalContainer {
private SQLContainer parentContainer;
private SQLContainer childContainer;
private String parentPrimaryKey;
private String childForeignKey;
public TwoTableHierarchicalContainer(SQLContainer parentContainer, SQLContainer childContainer,
String parentPrimaryKey, String childForeignKey) {
this.parentContainer = parentContainer;
this.childContainer = childContainer;
this.parentPrimaryKey = parentPrimaryKey;
this.childForeignKey = childForeignKey;
init();
}
private void init() {
for (Object containerPropertyIds : parentContainer.getContainerPropertyIds()) {
addContainerProperty(containerPropertyIds, Object.class, "");
}
for (Object containerPropertyIds : childContainer.getContainerPropertyIds()) {
addContainerProperty(containerPropertyIds, Object.class, "");
}
for (Object itemId : parentContainer.getItemIds()) {
Item parent = parentContainer.getItem(itemId);
Object newParentId = parent.getItemProperty(parentPrimaryKey).getValue();
Item newParent = addItem(newParentId);
setChildrenAllowed(newParentId, false);
for (Object propertyId : parent.getItemPropertyIds()) {
#SuppressWarnings("unchecked")
Property<Object> newProperty = newParent.getItemProperty(propertyId);
newProperty.setValue(parent.getItemProperty(propertyId).getValue());
}
}
for (Object itemId : childContainer.getItemIds()) {
Item child = childContainer.getItem(itemId);
Object newParentId = child.getItemProperty(childForeignKey).getValue();
Object newChildId = addItem();
Item newChild = getItem(newChildId);
setChildrenAllowed(newParentId, true);
setParent(newChildId, newParentId);
setChildrenAllowed(newChildId, false);
for (Object propertyId : child.getItemPropertyIds()) {
#SuppressWarnings("unchecked")
Property<Object> newProperty = newChild.getItemProperty(propertyId);
newProperty.setValue(child.getItemProperty(propertyId).getValue());
}
}
}
}
I am building composite WPF application using MVVM-light. I have Views that have ViewModels injected into them using MEF:
DataContext = App.Container.GetExportedValue<ViewModelBase>(
ViewModelTypes.ContactsPickerViewModel);
In addition, I have ViewModels for each View (Screens and UserControls), where constructor usually looks like this:
private readonly ICouchDataModel _couchModel;
[ImportingConstructor]
public ContactsPickerControlViewModel(ICouchDataModel couchModel)
{
_couchModel = couchModel;
_couchModel.GetContactsListCompleted+=GetContactsListCompleted;
_couchModel.GetConcatcsListAsync("Andy");
}
Currently, I have some performance issues. Everything is just slow.
I have 2 kind of related questions
What is the right way of calling DAL methods asynchronously (that access my couchdb)? await/async? Tasks? Because currently I have to write a lot of wrappers(OnBegin, OnCompletion) around each operation, I have GetAsyncResult method that does some crazy things with ThreadPool.QueueUserWorkItem , Action etc.
I hope there is the more elegant way of calling
Currently, I have some screens in my application and on each screen, there are different custom UserControls, some of them need same data (or slightly changed) from DB.
Questions: what is the right way to share datasource among them? I am mostly viewing data, not editing.
Example: On Screen A: I have Contacts dropdown list user control (UC1), and contact details user control(UC2). In each user control, their ViewModel is calling DAL:
_couchModel.GetConcatcsListAsync("Andy");
And on completion I assign result data to a property:
List<ContactInfo> ContactsList = e.Resuls;
ContactsList is binded to ItemsSource of DropDownListBox in UC1. The same story happens in UC2. So I end up with 2 exactly same calls to DB.
Also If I go to Screen B, where I have UC1, I’ll make another call to DB, when I’ll go to Screen B from Screen A.
What is the right way to making these interaction ? e.g. Getting Data and Binding it to UC.
Thank you.
Ad.1
I think you can simply use Task.Factory to invoke code asynchronously (because of that you can get rid off OnBegin, OnCompletion) or if you need more flexibility, than you can make methods async.
Ad. 2
The nice way (in my opinion) to do it is to create DatabaseService (singleton), which would be injected in a constructor. Inside DatabaseService you can implement some logic to determine whether you want to refresh a collection(call DAL) or return the same (it would be some kind of cache).
Then you can call DatabaseService instead of DAL directly and DatabaseService will decide what to do with this call (get collection from DB or return the same or slightly modified current collection).
Edit:
DatabaseService will simply share a collection of objects between ViewModels.
Maybe the name "DBCacheService" would be more appropriate (you will probably use it only for special tasks as caching collections).
I don't know your architecture, but basically you can put that service in your client application, so the plan would be:
Create DatabaseService.cs
[Export(typeof(IDatabaseService))]
public class DatabaseService : IDatabaseService
{
private List<object> _contacts = new List<object>();
public async Task<List<object>> GetConcatcsList(string name)
{
if (_contacts.Count == 0)
{
//call DAL to get it
//_contacts = await Task.Factory.StartNew(() => dal.GetContactsList(name));
}
else
{
//refresh list if required (there could be some condition)
}
return _contacts;
}
}
Add IDatabaseService to your ViewModel's constructor.
Call IDatabaseService instead of DAL.
If you choose async version of DatabaseService, then you'll need to use await and change your methods to async. You can do it also synchronously and call it (whenever you want it to be asynchronous) like that:
Task.Factory.StartNew(() =>
{
var result = dbService.GetContactsList("Andy");
});
Edit2:
invoking awaitable method inside Task:
Task.Factory.StartNew(async () =>
{
ListOfContacts = await _CouchModel.GetConatcsList ("Andy");
});
I know this question has been asked and discussed a lot (e.g. Here and Here and this Article). Nevertheless, i still feel confused about it. I know that DbContexts should not live for the duration of application lifetime, i know they should be used per Form (window) or per Presenter. The problem is that i don't have Forms or Presenters. I have a single Form (Window) with many view models, some of them which live for the duration of the application and almost all of my view models depend on DbContext (LOB application, WPF, MVVM, Sql Server CE).
My solution is to hide DbContext behind a factory which is injected in all view models that need access to DbContext and those view models create/dispose of the DbContext when their corresponding view is loaded/unloaded.
I would like to know if this solution has any problems or if there is a better solution you could advise ?
I tend to lay my projects out as follows;
1) Presentation Layer:
Contains my Views and ViewModels
2) Business Layer:
Contains my business logic
3) Data Layer:
Contains my models
My Presentation layer calls into the business layer to populate local copies (held in the ViewModel) of the data I wish to use in my ViewModel / View.
This is achieved with a Using statement, something like;
Using DBContext As Entities = ConnectToDatabase()
Dim clsApprovalTypes As New Repositories.clsApprovalTypesRepository(DBContext)
dbResults = clsApprovalTypes.GetRecords()
End Using
Return dbResults
Here I simply pass in the Context into Repository, once the data has been returned, the "End Using" will dispose of my context.
To update the context with changes made in my ViewModel / View, I use an AddEdit routine, which accepts a record, and updates / Adds to the context as necessary, using a similar methodology to the above, something like;
Using DBContext As CriticalPathEntities = ConnectToDatabase()
Dim clsApprovalTypes As New Repositories.clsApprovalTypesRepository(DBContext)
clsApprovalTypes.AddEditRecord(ApprovalTypeToSave)
Try
clsApprovalTypes.SaveData()
Catch ex As Exception
Return ex
End Try
End Using
Where my AddEdit routine is something like;
SavedRecord = New ApprovalType 'Store the Saved Record for use later
Dim query = From c In DBContext.ApprovalTypes
Where c.ApprovalType_ID = RecordToSave.ApprovalType_ID
Select c
If query.Count > 0 Then
SavedRecord = query.FirstOrDefault
End If
'
' Use Reflection here to copy all matching Properties between the Source Entity
' and the Entity to be Saved...
'
SavedRecord = Classes.clsHelpers.CopyProperties(RecordToSave, SavedRecord)
If query.Count = 0 Then
Try
DBContext.ApprovalTypes.Add(SavedRecord)
Catch ex As EntityException
Return ex
End Try
End If
I wrote a little more about some of this here;
https://stackoverflow.com/a/15014599/1305169
I am converting an asp.net MVC application to silverlight, and due to the fact I was doing some 'non-standard' things in my mvc app, I am having a hard time trying to work out how to implement it in Silverlight MVVM.
Basically I was generating all my views from metadata, including links, buttons etc. One example of this that I can't get my head around how to do in Silverlight is that I passed in an action collection to my view, and had a html helper class that then converted these actions into links
public static string GenericLinks(this HtmlHelper htmlHelper, int location, bool inTable, int? parentRecordId, List<ModelAction>
actions)
{
int actionNo = 1;
StringBuilder text = new StringBuilder();
foreach (var action in actions)
{
if (action.LocationType == location)
{
if (inTable)
text.Append("<td>");
else
if (actionNo > 1)
text.Append(" | ");
text.Append(htmlHelper.ActionLink(action.Label, action.ActionTypeLookup.CodeName, new { actionId = action.ModelActionId,
parentRecordId = parentRecordId }));
if (inTable)
text.Append("</td>");
actionNo++;
}
}
return text.ToString();
}
This really worked well in MVC.
What would the equivent be in MVVM?
I would expect I could do something much more eligent, more along the lines of creating my actions in my viewmodel, and somehow binding to those actions in my view...
For something like that you would probably need to create a custom control. Then you could put it in your view and bind it to the collection of Actions which would exist in your ViewModel.
I have a problem with Linq and ObservableCollections in my WPF application.
Context of the problem:
I've created a very simple SQL database with two tables: User and BankAccounts.
The User Table has an one-to-many relationship with the BankAccounts Table. Next I've created Linq-to-SQL dataclasses, which worked fine ==> the assosiation between the two tables was detected as well.
Next I've created a function to retreive all Users which works fine:
DataClassesDataContext dc = new DataClassesDataContext
var query = from u in dc.Users
select u;
Now suppose I want to add a new BankAccount to each user (not very likely but still).
I could add the following code
for each(User u in query)
{
u.BankAccounts.Add(New BankAccount());
}
The above works all fine. The BankAccounts property is automaticly part of the User class, due to the assosiation in the database and Linq DataClasses.
However, in my application I first add the query results to an ObservableCollection. Hereby I could use all sorts off databinding and changenotification. This is accomplished by the following code;
ObservableCollection<User> oUsers = new ObservableCollection<User>(query);
Problem: Within the ObservableCollection I can't do anyting with the users BankAccounts property because it is now of type EntitySet<>. So I can't do the following statement anymore.
for each(User u in oUsers)
{
u.BankAccounts.Add(New BankAccount());
}
Somehow, when queryresults are added to an observablecollection It is not possible to acces the user.BankAccounts properties anymore. However, it is possible to bind the BankAccounts Property to any control, like a listbox, and it contains the correct data.
Does someone now how I can create an observableCollction (or similar collection) from wich I can access these "assosiated" properties? I'm realy looking forward for to a solution.
Thanks in advance!
Best regards,
Bas Zweeris
E: Bas.Zweeris#Capgemini.com
Keep track of the original query which will implement IQueryable, you can run any further queries you need against that.
The ObservableCollection should just be for WPF to have something to bind to - its very useful if you want to add a new collection item but not have it pushed to the database before the user has had chance to edit it.
eg.
// Create a new blank client type
var ct = new ClientType()
{
IsArchived = false,
Description = "<new client type>",
Code = "CT000",
CanLoginOnline = true
};
// Tell the data source to keep track of this object
db.ClientTypes.InsertOnSubmit(ct);
// Also add the object to the observable collection so that it can immediately be shown in the UI and editted without hitting the db
clienttypes.Add(ct);