I have 2 maps that I want to throw into the same source. But it seems one source overrides the second source even though I am targeting different fields.
public class FormViewModel
{
public List<SelectListItem> Items { get; set; }
public string SelectedItem { get; set; }
public string SomeField {get; set;}
// I have many more
}
List<Items> items = Service.GetItems();
FormViewModel viewModel = new FormViewModel()
{
Items = Mapper.Map<List<Items>, List<SelectListItem>>(courses);
};
var fields = Service.GetFields();
viewModel = Mapper.Map<Fields, FormViewModel>(fields);
So now when I do the second map. It will wipe out my first map. How can I stop this?
Edit
I guess I can see why it is happening. I thought it was just filling in those the fields but now I am looking at it and seeing that it is return a new FormViewModel.
I guess I can rearrange my code so that I first do the last map first then add my other map after.
List<CalendarAppointmentReminderVM> vm = Mapper.Map<List<CalendarAppointment>, List<CalendarAppointmentReminderVM>>(taskReminders.Select(x => x.CalendarAppointment).ToList());
Mapper.Map<List<AppointmentReminder>, List<CalendarAppointmentReminderVM>>(taskReminders, vm);
Separately they work. But together the first result gets wiped out by the first one.
pass the output of the first mapping into the second mapping so it doesn't create a new one...
viewModel = Mapper.Map<Fields, FormViewModel>(fields, viewModel);
Related
I have an issue trying to get a Checkbox working with ObjectListview.
My model looks like this:
public class object
{
public string name {get; set;}
public int age {get; set;}
public bool inuse {get; set;}
}
And I added a FastObjectListView via the Designer in Visual Studio to a Win Forms Application.
Then, I added the Columns and set the AspectName for each column to the Models Property (First column: AspectName: name, Second Column: AspectName: age, Third Column: AspectName: inuse).
Afterwards, I filled the ListView with this:
using (var context = new objectDb())
{
var objectlist = context.objects.ToList();
fastoLV_Clean.SetObjects(objectlist);
fastoLV_Clean.Refresh();
}
That works, and I can see my Database entries in the ListView.
Now I want to add a CheckBox column where someone can check or uncheck the items to delete them and I can not get the checkbox to work.
I have added a Column and set CheckBox to true, changed the CheckedAspectName of the ListView and now I can see the Checkboxes but nothing happens if I click them to check.
I think I'm on the completely wrong track, what do I have to do to make it work?
Thank you very much!!
I don't know a way with the ObjectListView to include any items which are not part of your model.
So then the simple way is to change your model to include a "Delete" property which you can then show in your ObjectListView.
Of course, this is not always possible! Especially if you are dealing with items that are written to/from Database or another persistence layer.
Then the trick is to write a derived class with you model being the base class and then you just add the delete column to this. But then you would need to convert from your Base to a derived class before showing in the ObjectListView.
The following code can help with that.
You keep your columns set-up as you have already done.
Assuming your (now base) class is defined like this
public class MyClass
{
public string name { get; set; }
public int age { get; set; }
public bool inuse { get; set; }
}
Your derived class inherits from this, adds the delete property and a new constructor
public class MySecondClass : MyClass
{
public bool Delete { get; set; }
public MySecondClass(MyClass other)
{
//Copy from MyClass
this.name = other.name;
this.age = other.age;
this.inuse = other.inuse;
//Set default for new properties
this.Delete = false;
}
}
Your code to retrieve the objects and set them then looks like this
using (var context = new objectDb())
{
var objectlist = context.objects.ToList();
//Now we need to convert to the derived class type
var secondlist = list.ConvertAll(x => new MySecondClass(x));
//Then we setobjects using this new list
fastoLV_Clean.SetObjects(secondlist);
}
I have a list that I prepare in a ViewModel to take values from database table. The list assigned into a model class:
public class DType
{
public string DTName { get; set; }
}
And it get updated by the following method:
public static List<DType> GetDocTypesString(Entity DB, int RKey)
{
return DB.Database.SqlQuery<DType>(#"SELECT * FROM Names
WHERE NK = {0}", RKey).ToList();
}
And then I return the list (model) to the view to list the names into a select menu as the following:
The actual returned model to the view:
public List<DType> ihName { get; set; }
it gets populated by using the method above:
ihName = GetDocTypesString(DB, RKey);
And then, in the view, I use the below:
#Html.Partial("GettingNamesPartial", new ProjName.ViewModels.UploadingPartialViewModel
{
DropdownIHDocType = new SelectList(Model.ihEditorInstanceName)
})
The results are always like this:
Instead to displaying the actual names, the list (select) display:
ProjName.ViewModels.DType
ProjName.ViewModels.DType
ProjName.ViewModels.DType
ProjName.ViewModels.DType
The only thing that matches is the number of items is the same as the names on the database table.
Important Note:
Before trying to pull the names from the database, the list worked just fine by hard coding the names like the following:
DropdownIHDocType = new SelectList(new string[] { "Morgan", "Sam", "Shawn" })
ihName = GetDocTypesString(DB, RKey);
is your culprit. your getting a list of document types, not the variable name from each of those documents. basically your showing the class not its content. you need to get access to the actual document, then find the variable you need and assign that to ihName
so you're grabbing DType not DType.DTname which is what i assume your trying to list
I have a class setup like this:
public class Summary
{
public Geometry geometry { get; set; }
public SummaryAttributes attributes { get; set; }
}
public class SummaryAttributes
{
public int SERIAL_NO { get; set; }
public string District { get; set; }
}
public class Geometry
{
public List<List<List<double>>> paths { get; set; }
}
and i take a json string of records for that object and cram them in there like this:
List<Summary> oFeatures = reportObject.layers[0].features.ToObject<List<Summary>>();
my end goal is to create a csv file so i need one flat List of records to send to the csv writer i have.
I can do this:
List<SummaryAttributes> oAtts = oFeatures.Select(x => x.attributes).ToList();
and i get a nice List of the attributes and send that off to csv. Easy peasy.
What i want though is to also pluck a field off of the Geometry object as well and include that in my final List to go to csv.
So the final List going to the csv writer would contain objects with all of the fields from SummaryAttributes plus the first and last double values from the paths field on the Geometry object (paths[0][0][first] and paths[0][0][last])
It's hard to explain. I want to graft two extra attributes onto the original SummaryAttributes object.
I would be ok with creating a new SummaryAttributesXY class with the two extra fields if that's what it takes.
But i'm trying to avoid creating a new anonymous object and having to delimit every field in the SummaryAttributes class as there are many more than i have listed in this sample.
Any suggestions?
You can select new anonymous object with required fields, but you should be completely sure that paths has at least one item in each level of lists:
var query = oFeatures.Select(s => new {
s.attributes.SERIAL_NO,
s.attributes.District,
First = s.geometry.paths[0][0].First(), // or [0][0][0]
Last = s.geometry.paths[0][0].Last()
}).ToList()
Got it figured out. I include the X and Y fields in the original class definition. When the json gets deserialized they will be null. Then i loop back and fill them in.
List<Summary> oFeatures = reportObject.layers[0].features.ToObject<List<Summary>>();
List<Summary> summary = oFeatures.Select(s =>
{
var t = new Summary
{
attributes = s.attributes
};
t.attributes.XY1 = string.Format("{0} , {1}", s.geometry.paths[0][0].First(), s.geometry.paths[0][1].First());
t.attributes.XY2 = string.Format("{0} , {1}", s.geometry.paths[0][0].Last(), s.geometry.paths[0][1].First());
return t;
}).ToList();
List<SummaryAttributes> oAtts = summary.Select(x => x.attributes).ToList();
I want to filter an ObservableCollection of Person object by name for my Xamarin Form application.
The goal is to filter this ObservableCollection to just display a part of it.
Here is my Person object class :
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
}
I tried to make a filter like this :
private ObservableCollection<Person> personItems = new ObservableCollection<Person>();
public ObservableCollection<Person> PersonItems
{
get { return personItems; }
set { personItems = value; OnPropertyChanged(); }
}
public void FilterPerson(string filter)
{
if (string.IsNullOrWhiteSpace(filter))
{
PersonItems = personItems;
}
else
{
PersonItems = personItems.Where((person) => person. Name.ToLower().Contains(filter));
// Error here
}
}
I have this error :
Cannot not explicitly convert type :
'System.Collections.Generic.IEnumerable' to
'System.Collections.ObjectModel.ObservableCollection
Basically, there are two solutions:
If your PersonsItems list is not huge, you may recreate a whole collection each time a new filter string arrives. You don't even need an ObservableCollection in this case (due to the fact that you don't change the collection itself, you change a reference to a collection). All the UI elements will be recreated in this case
PersonItems = originalItems.Where((person) => person. Name.ToLower().Contains(filter)).ToList();
If your PersonsItems list is big enough, the first solution is not an option. In this case you need to manually call Add/Remove methods on the objects that should be added/removed. ObservableCollection has an imperative API and it fires an event each time Add/Remove is called. This event, in turn, can be observed by the ItemsControl that will make corresponding UI changes. Linq has a declarative API. That's why u need to sync a list to show with a filtered list manually.
PersonItems = personItems.Where((person) => person. Name.ToLower().Contains(filter));
is returning IEnumerable.
replace it with PersonItems = new ObservableCollection<Person>(personItems.Where((person) => person.Name.ToLower().Contains(filter)));
You have to recreate the observable using the filtered results.
To do this in the past I've used James Montemagno's ObservableRangeCollection and Grouping helper functions. You can find them in this plugin https://github.com/jamesmontemagno/mvvm-helpers
Lets imaging the we have model:
public class InheritModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string OtherData { get; set; }
}
We have a controller with View, that represents this model:
private InheritModel GetAll()
{
return new InheritModel
{
Name = "name1",
Description = "decs 1",
OtherData = "other"
};
}
public ActionResult Index()
{
return View(GetAll());
}
Now we can edit this in View, change some data and post in back to server:
[HttpPost]
public ActionResult Index(InheritModel model)
{
var merged = new MergeModel();
return View(merged.Merge(model, GetAll()));
}
What i need to do:
In view we have a reproduction of model
User change something and post
Merge method need to compare field-by-field posted model and previous model
Merge method create a new InheritModel with data that was changed in posted model, all other data should be null
Can somebody help me to make this Merge method?
UPDATE(!)
It's not a trivial task. Approaching like:
public InheritModel Merge(InheritModel current, InheritModel orig)
{
var result = new InheritModel();
if (current.Id != orig.Id)
{
result.Id = current.Id;
}
}
Not applicable. It's should be Generic solution. We have more than 200 properties in the model. And the first model is built from severeal tables from DB.
public InheritModel Merge(InheritModel current, InheritModel orig)
{
var result = new InheritModel();
if (current.Id != orig.Id)
{
result.Id = current.Id;
}
if (current.Name != orig.Name)
{
result.Name = current.Name;
}
... for the other properties
return result;
}
Another possibility is to use reflection and loop through all properties and set their values:
public InheritModel Merge(InheritModel current, InheritModel orig)
{
var result = new InheritModel();
var properties = TypeDescriptor.GetProperties(typeof(InheritModel));
foreach (PropertyDescriptor property in properties)
{
var currentValue = property.GetValue(current);
if (currentValue != property.GetValue(orig))
{
property.SetValue(result, currentValue);
}
}
return result;
}
Obviously this works only for 1 level nesting of properties.
Per topic, it seems that what you want is a sort of "change tracking" mechanism which is definitely not trivial or simple by any means. Probably, it makes sense to use any modern ORM solution to do that for you, does it?
Because otherwise you need to develop something that maintains the "context" (the 1st level object cache) like EF's ObjectContext or NH's Session that would be generic solution.
Also, there is no information on what happens at the lower level - how do you actualy save the data. Do you already have some mechanism that saves the object by traversing it's "non-null" properties?
I have a similar project experience, which made me thought a lot about the original design. Think the following question:
You have a view that representing a model, then users modified
something of the model in the view, all the CHANGES are posted to
server and the model is modified, and then it's saved to database
probably. What's posted to the server on earth?
An instance of InheritModel? No. You want the changes only. It's actually part of InheritModel, it's a InheritModel Updater, it's an instance of Updater<InheritModel>. And in your question you need to merge two models, because your Update method looks like:
public InheritModel Update(InheritedModel newModel)
{
//assign the properties of the newModel to the old, and save it to db
//return the latest version of the InheritedModel
}
Now ask yourself: why do I need a whole instance of InheritedModel when I just want to update one property only?
So my final solution is: posting the changes to the controller, the argument is something like a Updater<TModel>, not TModel itself. And the Updater<TModel> can be applied to a TModel, the properties metioned in the updater is assigned and saved. There shouldn't a MERGE operation.