Binding to a DataGrid column-wise? - mvvm

I have a datagrid with two columns and need to bind data column-wise i.e,
(0,0) (0,1)
(1,0) (1,1)
.....
(n,0) (n,1)
I am following MVVM pattern in my application. In each sell i am going to display same set of controls whose values are bound. Is it possible to get this??
How to achieve this using MVVM???

Doesn't seem any different than a normal binding. If I were doing this, I'd have an OC of types that hold each row of data
public ObservableCollection<Row> Rows {get;set;}
that I'd fill will Row instances (leaving out all INPC wiring)
public sealed class Row
{
public object ColumnOne {get;set;}
public object ColumnTwo {get;set;}
}
and I'd just bind that collection to the ItemsSource
<DataGrid ItemsSource="{Binding Rows}">

Related

How to have two different navigation properties of the same another entity type using attributes

I have two entities:
//The master table/entity
[TABLE("POSITIONS")]
public class Position{
[Key,Column("POSITIONID")]
public int PositionId{get;set;}
[Column("POSITIONNAME")]
public string PositionName{get;set;}
}
//The detail table/entity
[TABLE("SLAVE_POSITIONS")]
public class SlavePosition{
[Key,Column("MASTERPOSID",Order=0)]
public int MasterPosId{get;set;}
[KEY,Column("SLAVEPOSID",Order=1)]
public string SlavePosId{get;set;}
[ForeignKey("MasterPosId")]
public virtual Position MasterPosition {get;set;}
[ForeignKey("SlavePosId")]
public virtual Position SlavePosition {get;set;}
}
In the SlavePosition, as you can see, there two columns over which this entity is in FK relationship with Position. This layout works great. Now I also need to add this collection property to Position entity:
public virtual ICollection<SlavePosition> SlavePositions{get;set;}
But apparently EF gets confused and I get {"ORA-00904: \"Extent1\".\"Position_PositionId\": invalid identifier"} error.
If I declare it like this:
[ForeignKey("SlavePositionId")]
public virtual ICollection<SlavePosition> SlavePositions { get; set; }
and then fetch a Position with PositionId =1 like this:
Position pos= dbContext.Positions.SingleOrDefault(x=>x.PositionId==1);
I get no error, but I get SlavePOsitions count 0, when it should be 5 because in the database I have 5 rows in the detail table. I am able to confirm this by running the below code:
IEnumerable<SlavePositions> slavePositions= dbcontext.SlavePositions.Where(x=>x.MasterPositionId==1);
I get five SlavePosition.
What should be the correct attribute for this collection property?
I finally figured it out. My mistake was in the referenced dependent property name. Instead of SlavePositionId I should put MasterPositionId.
This makes sense, because the Position entity acts as a master table and in real world Foreign Key relationship is set up on detail tables, not master ones. As there's no property in the dependent entity that has the same name as the PK in the master entity and there're more than one properties that have Foreignkey to the same master entity, EF needs more information.By specifying ForeignKey("MasterPositionId") to the ICollection navigation property, I instruct EF that Dependent end point property should be considered MasterPositionId. So I changed this
[ForeignKey("SlavePositionId")]
public virtual ICollection<SlavePosition> SlavePositions { get; set; }
to this
[ForeignKey("MasterPositionId")]
public virtual ICollection<SlavePosition> SlavePositions { get; set; }
In fact the former one itself is not wrong either, it just does not fit in this situation. But if I wanted to have a collection for MasterPositions this would fit perfectly fine.

Code First Entity Framework

We are using Miscrosoft's code first entity framework (4.1) to map to an existing database. We want to be able to change the datatypes and values of some properties that map one to one with a table. For instance, there is a column on the table that determines if a record is current. It is an integer column, and has values 1 or 2. We don't want to change the database as there are many different applications fetching data from that colum, but it would be nice for our code to have the class that maps to that table have a bool property that is IsActive, which returns true if the table column is 1 and false otherwise. Is there a way to configure the EnityFrame work so that we can define this mapping directly without having two properties on the actual class, one for the integer column (mapped to the database) and one boolean property computed from the other? Can I map the boolean property directly to the integer column?
Simple answer is no. EF is totally stupid in this area and it is completely missing simple type mapping.
That means that you cannot change type of scalar properties and your class indeed has to work with that int property using values 1 and 2 to define your IsActive.
The workaround can be:
public class YourClass
{
public int IsActiveValue { get; set; }
[NotMapped]
public bool IsActive
{
get { return IsActiveValue == 2; }
set { IsActiveValue = value ? 2 : 1; }
}
}
This workaround has some disadvantages
You must have two properties and IsActvieValue must be visible to context
You cannot use IsActive in linq-to-entities queries

Custom sort in domaincollectionview

I'm using a DCV as a property in the View Model.
Everything works fine but what about custom sort?
Say I have a string property in my model which should be sorted alphanumerically.
How can I achieve such thing?
UPD:
Model:
public class MyModel
{
///...
public SomeProperty {get;set;}
}
xaml:
<data:DataTextColumn Binding={binding path=SomeProperty}, canusersort=true />
When sorting within the datagrid, the property gets sorted with disregard to alphanumeric order, i.e. in a regular string way. I'd like to apply my custom sort, e.g. by introducing my own IComparer. No API is available at least as I know of it.
Any clues?
The DomainCollectioView has special collection:
SortDescriptions
You could add next code in Your ViewModel:
DCV.SortDescriptions.Add(new SortDescription("SomeProperty ", ListSortDirection.Ascending));

Getting Readonly Databind using EF POCO Objects

I am using EF4 with WPF. I am databinding to the DataGrid in a Master-Detail style. Think of the Northwind Customers -> Orders -> OrderDetails.
What I am finding is that when I use POCO objects, the Orders and OrderDetails grids are read-only. If I revert to using the designer generated entities they become editable.
The binding XAML looks like this:
<Window.Resources>
<CollectionViewSource x:Key="CustomersViewSource" d:DesignSource="{d:DesignInstance my:Customer, CreateList=True}" />
<CollectionViewSource x:Key="CustomersOrdersViewSource" Source="{Binding Path=Orders, Source={StaticResource CustomersViewSource}}" />
</Window.Resources>
<Grid DataContext="{StaticResource CustomersViewSource}">
<DataGrid ItemsSource="{Binding}" >
<DataGrid ItemsSource="{Binding Source={StaticResource CustomersOrdersViewSource}}" >
(I've removed attributes not relevant to databinding, of course.)
Then there's the standard form load event to bind the context instance:
Dim NorthwindEntities As BindTest.NorthwindEntities = New BindTest.NorthwindEntities()
Dim CustomersViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("CustomersViewSource"), System.Windows.Data.CollectionViewSource)
CustomersViewSource.Source = NorthwindEntities.Customers
The grids populate, but the second is readonly if I'm using my POCO objects, editable if they are the standard EF generated objects.
The key seems to be in the navigation properties of the entities. My POCO objects use:
Public Overridable Property Orders() As ICollection(Of Order)
Get
If _Orders Is Nothing Then _Orders = New HashSet(Of Order)
Return _Orders
End Get
Set(ByVal value As ICollection(Of Order))
_Orders = value
End Set
End Property
Whereas the EF objects are much more complicated:
<XmlIgnoreAttribute()>
<SoapIgnoreAttribute()>
<DataMemberAttribute()>
<EdmRelationshipNavigationPropertyAttribute("NorthwindModel", "FK_Order_Details_Orders", "Orders")>
Public Property Order() As Order
Get
Return CType(Me, IEntityWithRelationships).RelationshipManager.GetRelatedReference(Of Order)("NorthwindModel.FK_Order_Details_Orders", "Orders").Value
End Get
Set
CType(Me, IEntityWithRelationships).RelationshipManager.GetRelatedReference(Of Order)("NorthwindModel.FK_Order_Details_Orders", "Orders").Value = value
End Set
End Property
For the lack of some better wording, there seems to be some magic in either the attributes for the EntityCollection type. ICollection isn't a readonly interface and a HashSet isn't readonly either.
Any ideas about how to get POCO to work here or am I stuck with EF derived objects? (Makes unit testing difficult.)
Thanks.
The problem is likely that the Orders and OrderDetails collections are of type ICollection<T> / HashSet<T> in your POCO example. The WPF datagrid internally does not work with the collection directly but rather with an associated "collection view". When you bind the collection to the DataGrid the WPF binding engine creates this internal collection view based on the type of the collection.
If your collection implements only IEnumerable or only ICollection the type of the created collection view is CollectionView, a class which does not implement IEditableCollectionView. That's the reason why you can't edit the DataGrid when you bind a HashSet to it.
The DataGrid needs a collection view which implements IEditableCollectionView to allow editing. This is for example the ListCollectionView (which also derives from CollectionView). WPF creates this type of collection view if your source collection implements the IList interface.
So, to fix the problem you should change the type of the Orders property of your POCO to IList:
Public Overridable Property Orders() As IList(Of Order)
Get
If _Orders Is Nothing Then _Orders = New List(Of Order)
Return _Orders
End Get
Set(ByVal value As IList(Of Order))
_Orders = value
End Set
End Property
Edit
According to #Allon Guralnek's comment below it is necessary to implement the non-generic IList interface to get an editable DataGrid. This is the case for List(Of T), therefore the code above will still work. Other implementations which only implement the generic IList(Of T) but not the non-generic IList won't make the DataGrid editable.

Page View Class Design

Suppose i have the following class.
public class Location
{
public Id { get; set;}
public Name { get; set;}
}
And i have a WebPage called Location that looks like this.
txtId
txtName
txtCountStaffWorkersAtLocation
txtCountVehiclesAtLocation
txtCountNonStaffWorkersAtLocation
txtCountetc
listViewPersonnel
listViewVehicles
Right now i'm calling a repository to display the Location fields on the view, but i'm confused as to what the correct method would be to get and display the data for the other fields. They obviously have very little to do do with the Location Class.
Do i put the Counts in the Location Class and fill them in when i set up the Location class from the database?
Do i have a struct object somewhere that has just has these count fields?
What do you guys normally do with object being displayed on a page that have very little to do with the Domain Object?
Thanks
I'd recommend implementing StaffPersonnel, NonStaffPersonnel, and Vehicles as properties on the Location object, with each of those properties returning a collection of the associated objects. Then for the counts, you could properties from a location object as follows:
loc.Vehicles.Count
loc.StaffPersonnel.Count
loc.NonStaffPersonnel.Count