The title may sound a little strange, so I'll try to explain my problem:
Lets say I have a class that holds some Information:
class InfoHolder
{
public int MyInfo1 {get; set;}
public int MyInfo2 { get; set; }
}
Then I have another class, that does something with an info:
class InfoGUIRepresenter
{
// Display an int in some kind of GUI
// Allow the user to change the int via the GUI
}
Now I would need two objects of the representer class, to expose my Info-class to the user: One representer for each of the two infos. To achieve that it would be nice to pass each of the properties as some kind of "parameter" to my representer classes.
But of course that's not possible in C#. Another solution would be to pass the names of the properties and then use reflection to access them - not very nice!
Is there any solution to this? Maybe some kind of architecture that addresses this kind problem?
Thanks!
One option is to pass two delegates - one for the setter and one for the getter:
var holder = new InfoHolder();
var representer = new InfoGUIRepresenter(() => holder.MyInfo1,
value => holder.MyInfo1 = value);
Then your InfoGUIRepresenter constructor would take a Func<int> and an Action<int>. (Or you could make the representer generic, for different types of property.)
You mention display "in some kind of GUI" which implies you are using a GUI framework. Surely that framework supports a well defined model for this sort of situation. Eg MVVM if you are using WPF (your info objects are models, your UI is a view and you can do binding from view to model via view model properties bound to UI element properties). I.e are you not trying to reinventing the wheel here?
Related
I'm new at WPF and I'm trying to use MVVM. I'm using CollectionViewSource in my view-model against a SQL database using Entity Framework.
So let's say I have this class:
public class People
{
public int Id { get; set; }
public string name { get; set; }
}
And lets say this is what I have in the database:
ID: Name:
Bugs Bunny
Mick Jagger
Mickey Mouse
Donald Duck
Goofy
Elmer Fudd
Daffy Duck
Porky Pig
Now using CollectionViewSource.View, I know how to use the methods MoveCurrentToNext(), MoveCurrentToPrevious(), etc. and that works fine, but I need to move to a specific name, for example Donald Duck. So if I do this:
dbContext.Peoples.Find(4);
Or if I do this
dbContext.Peoples.Where(p => p.Name == "Donald Duck").FirstOrDefault();
That will get me the right object from the database using Entity Framework. However, if I do this:
CollectionViewSource.View.MoveCurrentTo(dbContext.Peoples.Find(4));
It will not move, and CollectionViewSource.View.CurrentItem is null.
So then how would someone move to the correct item?
I guess this is because the reference that you get when calling dbContext.Peoples.Find(4) is not the same as the one you have in your CollectionView source collection.
The CollectionViewSource.View.MoveCurrentTo (an others 'MoveTo' methods of the collectionView) requires an argument that is the same reference as the one in your source collection.
Then, if your dbContext methods to retreive an object returns a new instance or an instance different than the one in your CollectionView, this won't work.
So either use an intermediate collection as the source of the collection view to keep a unique reference to the objects (and update these references when the object in in data access context change) or try to implement equality members in your People class (never tried the later solution but should work).
Also, try to add in your question some complete piece of code rather than code fragments about which we can't realy see exactly where is the problem.
I am currently designing a class "User"
public class User
{
...
public int LocationId {get; set;}
public string LocationName
{
get
{
//Get name from the LocationList based on the LocationId
}
}
public List<SelectListItem> LocationList
{
get
{
//Retrieve the location as list from DB
}
}
....
}
My concern is that each time a new object is created, the DB will be accessed and the location list will be retrieved.
Can a class be created this way? Or is there a better way of doing it? Any help would be highly appreciated. Thanks.
The database would only be hit when LocationList was accessed, not when the class is newed up. However, no, this is not the best way. Entity classes / view models should not interact with your context directly. The biggest reason for this is that you should really only have one and only one instance of your context and it's not always possible to properly inject it into these classes.
Instead, you should use a repository or service class to abstract away the query and then simply set the list property directly in your controller action by calling some method on your repository or service.
There is one point in addition to what Chris mentioned, take a look on this rule:
CA1002: Do not expose generic lists.
So in general, the class shouldn't expose any property returning a generic list. Try to use one of these:
System.Collections.ObjectModel.Collection
System.Collections.ObjectModel.ReadOnlyCollection
System.Collections.ObjectModel.KeyedCollection
It's almost always a good idea to make a repository whenever an external system/source should be communicated with.
In that way you have all logic that interacts with a given source in one place and can debug and edit it in that one specific place. Plus you should only have a single database context in use at any given time anyway as Chris Pratt mentions.
I am struggling to implement MVVM pattern in my current project.
"ClassA" continuously gets required data from a remote device and stores this data inside it's fields. It is a model, I guess. ClassA updates required information via Update method.
"ClassB" continuously gets the data from "ClassA" and stores it in corresponding properties. Looks like it is a view model.
View is a simple MainWindow.xaml with a DataGrid inside.
I have the following questions:
1) How do I update ViewModel?
Should ClassB have an Update method, which accepts an instance of ClassA and updates corresponding fields?
2) Where do I store an instance of ClassA?
Should ClassA be a field of ClassB? If it should, then how do I update Model?
I thought of something like the following:
public void UpdateB()
{
ClassA.UpdateA();
this.FieldOne = ClassA.FieldOne;
this.FieldTwo = ClassA.FieldTwo;
}
4) Does model have it's update method at all or model just stores the data?
3) What do I do inside MainWindow.cs, aside from windows initialization? Do I update view model (ClassB) there?
I find it best to have a object representing an item in each layer of abstraction. This includes the form of the data as it exists on the disk. Remember that in MVVM, the only real goal is to promote loose coupling between the interface(User Interface) and the implementation(ViewModel functionality).
For example, if I have objects stored in XML files, I will have an object in my data access layer that exists only for the proper management of the XML data. Let's call it ObjectXml. This object only contains data in the form that is native to the data on the disk. In this case, all data has a string representation, as in the XML files.
In the model layer, you will have the data representation of the XML file in the expected data types. Let's call this Object. The property getters and setters may access and set the string representation of the data by performing conversions in both directions. This way, the data is ready to be persisted to the data source(xml file, database etc.).
In ObjectViewModel, properties may access those in Object. The viewmodel contains all the members for representing and modifying the model.
Note that ObjectXml is really only beneficial when you are only allowed to store string information, or when a suitable schema does not exist for your data types.
At the end, you have a hierarchy of containment such as the one below:
public class ObjectXml
{
[XmlArray("People"), XmlArrayItem("Person")]
public List<PersonXml> People { get; set; }
//PersonXml is an xml data model similar to this one
[XmlElement("Item")]
public string Items { get; set; }
}
Here is the model for the Xml object:
public class Object
{
private ObjectXml _xmlContext;
public Object(ObjectXml xmlContext)
{
this._xmlContext = xmlContext;
}
public List<Person> People
{
get
{
//Person requires a constructor that takes a PersonXml object in order for this to work properly
return this._xmlContext.People.Select(x => new Person(x)).ToList();
}
set
{
this._xmlContext.People = value.Select(x => new PersonXml(x)).ToList();
}
}
public double Item
{
get { return double.Parse(this._xmlContext.Item); }
set { this._xmlContext.Item = value.ToString(); }
}
}
Obviously, it's not wise to name your class Object as it's a reserved word in C#. Hopefully I've given you some ideas of how to access and update data in a robust and extensible manner.
In short, you don't need an update method at all. Also, short of constants and property backing fields, there are very few reasons to need direct field access in C# MVVM.
See below. Do not listen to people that say the ViewModel and Model need to be decoupled. The main purpose of the model is an intermediary layer that prepares data to be saved or loaded into the program and to store data in a way that is agnostic to both the data and the program functionality(ViewModel)
You do not need an update method. Use properties that access the data model and persist to the data storage(xml, database etc.) if needed.
You do not need an update method.
You should not have to do anything inside of ViewModel.cs. Only code that modifies the view should be in the codebehind. The only ViewModel you should ever access in a view is one that follows the form of MainWindowViewModel, which is more like an ApplicationViewModel that carries instances of other required viewmodels.
Finally, don't get stuck using an overcomplicated MVVM "framework" as most of the functionality is not useful or necessary.
Like stated in Yuris comment, you should not use any update method, but rather implement the INotifyPropertyChanged interface. Like the name says this notifies all subscribers when the value of a certain Property changed.
This is a nice article which contains code to a minimalistic MVVM implementation. If you have trouble implementing the pattern from scratch, try to start with this example and replace the existing classes with your own one-by-one.
As to the update mechanic inside your MainWindow.cs - you don't need any, if you specify the DataBinding in your xaml code like it is done in the example linked above.
I hope this helps you getting started!
I am working on ASP.NET MVC 4 project. I have ViewModel which is :
public class SectionModel
{
public Menu Menu { get; set; }
public IList<Document> Documents { get; set;}
}
then in my action I have :
Menu menu = unitOfWork.MenuRepository.GetById(Id);
IList<Document> docs = unitOfWork.DocumentRepository.GetBy(x => x.MenuID == menu.MenuID).ToList();
SectionModel model = new SectionModel();
model.Menu = menu;//???
model.Documents = docs;//???
So menu and docs are fetched from the database. The when I create new instance of SectionModel I want to pass the values but I'm not sure what's the proper way. In fact what is the way to assign the single object menu and the IList<Document> docs?
I was thinking of model.Menu.Add(menu) and then some foreach like:
foreach (var doc in docs)
{
model.Documents.Add(doc);
}
but I'm not sure that's the proper way to do this.
There's a common thread of thought I see all the time, about using interfaces to declare lists (or some other collection type) when declaring properties. I understand the motivation to do this, should you ever decide to throw the standard .NET List<> class in favour of your home-grown.
I've yet to see a decent reason for this. You're falling foul of the "let's abstract everything away in all circumstances, even if they are not particularly relevant" idiom. (And let us not forget that interfaces on POCOs are not particularly ORM-friendly.)
If I were designing an API, I might use IList, even if everything worked with a List internally. Truth is, it's a bit of a misnomer. I've never had cause to use an IList<> because that's all it is... a programmatic misnomer.
As Julie says, swap out that interface and put a decent class in there (List<>, for example).. not only is it concrete, but you can then use it as it should be used. People love to band about the terms of interfaces always in case I change my mind but that just stinks of bad design.
Don't be afraid to use a real, concrete class.
I recommend interfaces if your code should inter-operate with others projects but underneath you are using always List<T>
you have to change this
public class SectionModel
{
public Menu Menu { get; set; }
public List<Document> Documents { get; set;}
}
and use
model.Documents.AddRange(docs);
If you consider to use AutoMapper, here's the code:
First, make sure you have AutoMapper installed. Use package-manager and type command package-install AutoMapper.
var anonymous = new {
Menu = unitOfWork.MenuRepository.GetById(Id);,
Documents = unitOfWork.DocumentRepository.GetBy(x => x.MenuID == menu.MenuID).ToList();
};
var sectionModel = AutoMapper.Mapper.DynamicMap<SectionModel>(anonymous);
Any why I suggest to use this ?
Point 1: IList is fine here. Somebody (or you) had put there during design and it's just fine. According to me, changing to List is unnecessary. Your model object is just there to put the information and IList is fine because your sectionmodel class is not going to change or delete any entry from it. Since its just there for enumeration its fine.
Point 2: You can do the manual mapping. But, AutoMapper just maintains code readable.
In my Wpf project I try to seperate the view and the view-model.
I was thinking that e.g. the data-contract between view-model and model should be hidden from the view.
In practice however quite often you want to display a simple property from the data-contract in the view, which is not possible without a reference to the data-contract in the view.
E.g.
Properties.Settings.Default.Group = basedata.Groups.CurrentItem.Code;
requires a reference to the type of CurrentItem.
I could also expose a string property in the view-model like
public string CurrentGroupCode { get { return Groups.CurrentItem.Code; } }
This also looks so overdone. I tend to use the reference, because it results in less code.
Any objections?
Actually, I would go with your option 2. Why? Well if you want to implement the notification mechanism via INotifyPropertyChanged, this is the easiest way. If you want to pass values from model to the view and vice versa your example would look like this.
public SomeViewModel : ViewModelBase // assuming that you have a base class for this
{
public string CurrentGroupCode
{
get { return Groups.CurrentItem.Code; }
set
{
Groups.CurrentItem.Code = value; // assuming that the VM has been intialized correctly
RaisePropertyChanged("CurrentGroupCode"); // implemented in base class
}
}
/*
* ...Initialization, logic a.s.o.
*/
}
Means, if the business logic, which should also be implemented at the VM layer, modifies such a property, the view will be notified and updated automatically. Additionally, the modification will be propagated automatically to the model, too.
You see, with this approach you're not only hiding the model from the view, you're also providing a good modularity on the VM level, since the other VMs don't need to know something of the model structure.