I have 2 models, 2 views, and 1 viewmodel. Basically I want to load the data from a GTSLocation object into a ListItem, but also add two more values from a GTSWorkingSite object that has the same Working Site Guid as the GTSLocation object have.
The item fooA from ObservableCollection<GTSLocation>:
WorkingSiteId : "A-A-A-A"
Longitude: 60
Latitude: 120
The item fooB from ObservableCollection<GTSLocation>:
WorkingSiteId : null
Longitude: 70
Latitude: 130
The item barA from ObservableCollection<GTSWorkingSite>:
Id: "A-A-A-A"
Name: "WacDonald's"
Description: "A Fastfood resturaunt."
The listitem for fooA:
WorkingSiteName: "WacDonald's"
WorkingSiteDescription: "A Fastfood resturaunt."
Longitude: 60
Latitude: 120
The listitem for fooB:
WorkingSiteName: "Unknown Place"
WorkingSiteDescription: "No info to provide"
Longitude: 70
Latitude: 130
I can only come up with the solution that is to create another model which contain all the properties I want. Actually is it the only way to go? There must be a more elegant way I guess?
To add up, the reason I have two ObservableCollection is because GTSWorkingSite is also used on the other view (WorkingSiteView.xaml) seperately.
◎Model
public class GTSLocation
{
public string WorkingSiteId {get;set;} //GUID
public double Longitude {get;set;}
public double Latitude {get;set;}
public DateTime Timestamp {get;set;}
}
public class GTSWorkingSite
{
public string Id {get;set;} //GUID
public string Name {get;set;}
public string Description {get;set;}
}
◎ViewModel
public class GeneralViewModel : INotifyPropertyChanged
{
//Assume these two collection filled with data
public ObservableCollection<GTSLocation> UserLocations { get; set; }
public ObservableCollection<GTSWorkingSite> WorkingSites { get; set; }
//Ignored the rest of the code...
}
◎View: UserItemsPage.xaml
<ListView ItemsSource="{Binding UserLocations}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Image Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" />
<Label Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding WorkingSiteName}" />
<Label Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding WorkingSiteDescription}" />
<Label Grid.Row="2" Grid.Column="1" Text="{Binding Longitude}" />
<Label Grid.Row="2" Grid.Column="2" Text="{Timestamp}" HorizontalTextAlignment="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
If this is a bad design from the very begining, I am willing to refactor my code, if anyone could give me suggestion.
It's pretty bad because you rely on string (or whatever GUID) mapping between the two classes. If you don't want to create a third model but can refactor current model and if GTSLocation has a 1-1 mapping with GTSWorkingSite anyway then i think you could just do:
1) Refactor the model so that GTSLocation knows about the fact it has a GTSWotkingSite:
public class GTSLocation
{
public string WorkingSiteId {get;set;} //GUID
public double Longitude {get;set;}
public double Latitude {get;set;}
public DateTime Timestamp {get;set;}
//New property -> We will use it in the binding!
public GTSWorkingSite WorkingSite {get;set;}
}
public class GTSWorkingSite
{
public string Id {get;set;} //GUID
public string Name {get;set;}
public string Description {get;set;}
}
2) Then in your XAML it becomes easy to retrieve the info when populated correctly (note the binding ["."] slight change using the new added WorkingSite
property):
<ListView ItemsSource="{Binding UserLocations}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Image Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" />
<Label Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding WorkingSite.Name}" />
<Label Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding WorkingSite.Description}" />
<Label Grid.Row="2" Grid.Column="1" Text="{Binding Longitude}" />
<Label Grid.Row="2" Grid.Column="2" Text="{Timestamp}" HorizontalTextAlignment="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Hope it helps and happy coding!