I created a Custom Control for monodroid. Following the tutorial N-20 CustomControl and this MvxListView because my control binding a IEnumerable.
My control inherits to FrameLayout, then I don't have access to Adapter property from Parent Class.
When I assign the List binding property and call the RaisePropertyChanged event. Doesn't raise up. How can I do that?
Thanks in advance.
Edit to show code
Talk is cheap, I Show the code.
This is the header of custom control and the list of binding.
public class DrawingBoardControl : View
{
private DrawingItems m_drawingItems;
[MvxSetToNullAfterBinding]
public DrawingItems CanvasItems
{
get
{
return m_drawingItems;
}
set
{
m_drawingItems = value;
this.Update();
}
}
...
I use a class called "DrawingItems", there are
public class DrawingItems : IEnumerable<IDrawingElement>
{
private List<IDrawingElement> myDrawingItems = new List<IDrawingElement>();
public IEnumerator<IDrawingElement> GetEnumerator()
{
return myDrawingItems.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public void Add(IDrawingElement element)
{
myDrawingItems.Add(element);
}
}
However, in other custom controls I use a IEnumerable and generic List and the problem persist.
When, I use RaisePropertyChanged in my ViewModel, the Items property don't raise.
Sorry for not include more information yesterday
There are always some answers for uncomplete questions:
If you cannot access the Adapter of the parent, the parent has to set the context of the child. There are no more options. Make your custom control fully bindable by exposing the complete interfaces. The list has to provide the context for the list items.
Somehow a customcontrol binding to a IEnumerable feels very wrong. A custom control for displaying a list item, I can understand, but not for a list. But of course it can be done. But you end up setting references to the container class en setting the datacontext or viewmodel of each item.
But please provide more info if you want others to help.
UPDATE:
Then I also update :) This provides some clues of the problem:
Don't assign a new list, but inherit the this from ObservableCollection, or manually call the raiseProperty with the correct parameters in the setter. I think it is by design assigning a new list will not call PropertyRaised.
As the 'App is King'-rule: in this case I notify the propertychanged myself. It might have something to do with the weak references problem (see the attribute on the ListItem property).
Related
I've created FacesComponent which I want to initialize in constructor/postconstructor. The problem is that getAttributes() is empty in there. Below is the example.
#FacesComponent("articleComponent")
public class ArticleFacesComponent extends UINamingContainer {
private Article article;
public ArticleFacesComponent() {
Object idObj = getAttributes().get("articleId"); // I want to get article id to initialize object but getAttributes() is empty
...
article = em.find(Article.class, id);
}
}
You need to perform the job in the encodeAll() method. It's invoked during render response, when the component is about to be rendered.
#Override
public void encodeAll(FacesContext context) throws IOException {
// Here.
super.encodeAll(context);
}
Given that you're extending from UINamingContainer, you're most likely creating a backing component for a composite component. In that case, this article should provide you useful insights to get started: composite component with multiple input fields.
Unrelated to the concrete problem, accessing the DB in a component is a smell. Rather pass a fullworthy Article instance as component value instead of its ID. The component/renderer should only deal with front-end (HTTP/HTML) stuff based on the model, not with back-end (DB/SQL) stuff. You should provide the component exactly the model it needs to work with.
Like #BalusC said. But if you are using PrimeFaces you have to overwrite the encodeBegin() method. Else you may overwrite encodeAll().
I have a View which can be accessed when the Model is populated with data and when the Model is completely empty.
When the Model is empty, it means that the user clicked on "Create New".
At the moment, I am getting a NullReferenceException because there obviously isn't anything inside Model. If I pass an object over to the view then the browser just freezes because the object contains null items inside it.
Is there a quicker/better way of doing this instead of doing:
MyObject myObj = new MyObj();
myObj.InnerObj = new Object(){data = ....};
...
I hope that makes sense :)
You can use the NullObject pattern:
Create a subclass of MyObject that has all properties prepopulated and methods that purposefully implement no behavior. For instance:
public sealed class NullObject : MyObject
{
public object InnerObj { get; private set; }
public NullObject()
{
InnerObj = new Object { ... };
}
}
It may not be the most clever way to deal with it, but I will sometimes wrap the Model-dependent code in the view in
#if(Model.Property != null)
So if you're having a single view for 'Create' and 'Edit', with the difference being the population of properties in the model, test those properties with an 'if', then code accordingly.
A better solution (I think) that we eventually implemented is an enum that we call "EditState" with two values: 'create' and 'edit'. Make the EditState a property in the viewModel. Set or check it's value and render the view accordingly (either with inputs for create, or displays or however you're setting it up.) It's a nice and easy to read way to differentiate between the create flow and the edit flow.
I'm working on an ASP.NET MVC project that will allow users to perform batch edits on the attributes of objects. The implementation is in a sort of "wizard" like form with four phases to the process as follows:
"Select the attributes you want to edit" - the first page will present the user with a list of checkboxes representing each of the attributes they want to edit. The user should check the attributes they wish to edit and select "Continue".
"Edit the selected attributes" - the second page will present the user with a list of distinct "editors" which will be unique for each of the attributes they selected on the first page.
"Review your changes" - this page will allow the user to review the changes they've made to the attributes they selected.
"Submit your changes" - this page will actually submit the information about the edits the user wishes to make to the selected attributes against the selected collection of objects.
Fairly straight-forward.
As I mentioned, the "editor" will be unique to each attribute, and could have any combination of different controls on it. Once a user has made their edits and the application posts that information to the "Review" page is where I'm currently having my problem.
We've developed the concept of an "EditorWorker" class that is unique to each attribute, which is responsible for generating the ViewModel necessary for each editor, but is also responsible for creating/returning (within the "Review" page controller action) an object that is the "model" object for the editor that the post data can be bound to, which can then be use to display the edited data for review. This object should have properties that match up with the IDs of the controls in the editor so that model binding can occur.
I've got the "EditorWorker" creating and returning the class needed, but for some reason, when I call TryUpdateModel and pass in that class, its properties aren't getting populated as a result of that method call as I would expect them to. I have verified that the values are in the posted FormCollection. Below is the code for my controller action where I'm attempting to do this. If someone can help me understand why TryUpdateModel isn't working in this scenario, I would be very appreciative.
[HttpPost]
public virtual ActionResult Review(ReviewBatchViewModel model)
{
var selectedAttributes = GetSelectedAttributes(model.SelectedAttributeIds.Split(',').Select(i => Int64.Parse(i)).ToArray());
var workers = new List<IEditorWorker>();
var reviewData = new Dictionary<ViewAttribute, IEditData>();
foreach (var attribute in selectedAttributes)
{
if (!string.IsNullOrEmpty(attribute.EditorWorker)) // If there is no EditorWorker defined for this object, move on...
{
var worker = ServiceLocator.Current.GetInstance(Type.GetType(string.Format("{0}.{1}", EditorWorkerNamespace, attribute.EditorWorker)));
var attributeEditData = ((IEditorWorker)worker).LoadEditData();
if (TryUpdateModel(attributeEditData))
model.EditData.Add(attributeEditData); // model.EditData is a List<IEditData> that will be iterated on the Review page
reviewData.Add(attribute, attributeEditData);
}
}
return View(model);
}
// ReviewBatchViewModel.cs
public class ReviewBatchViewModel : BaseViewModel
{
public ReviewBatchViewModel() { EditData = new List<IEditData>(); }
public string SelectedAttributeIds { get; set; }
public List<ViewAttribute> SelectedAttributes { get; set; }
public List<IEditData> EditData { get; set; }
}
// IEditData.cs
public interface IEditData
{
}
// BroadcastStatusEditData.cs
public class BroadcastStatusEditData : IEditData
{
public int BroadcastStatus { get; set; }
}
I totally understand that this controller action is incomplete in its current state. I'm presently working on just trying to get those EditData objects populated correctly before I move on. As mentioned, any thoughts would be greatly appreciated. Thanks.
UPDATE: With regards to #mare's comment, I should have explained that part more clearly, sorry. The call to TryUpdateModel actually is returning true, but the fields on the model object being passed into it aren't actually being populated from the values that have been confirmed present in the posted form data. The model object being passed into the call is not a List, its just a poco. The resulting, ultimately hopefully populated model object is then being added to a List collection of model objects that will then be used for displaying the posted data for review on the Review page. I'm not loading anything from a datastore at all. Unique editors for each selected attribute are being rendered to the Edit screen, and I'm attempting to capture the edit values for display on a Review screen prior to submitting the batch of edits to a service. Hopefully that's more clear. Thanks.
UPDATE 2: I've included the definition of the ReviewBatchViewModel class as requested by #mare in the comments. The use of the var keyword in most cases in this code sample is largely due to the fact that the methods that are populating those variables is going to be returning an object of a different type for each attribute selected, so I never know exactly what its going to be at runtime (although it will always implement an interface, in this case either IEditorWorker and/or IEditData). There is a single class in the Model called "Attribute". The provided code sample has three variables relative that class: 1) SelectedAttributeIds is a comma-separated list of the Id's of the attributes that the user has selected to edit, which gets passed from the Edit page to the Review page via hidden field, 2) selectedAttributes is a collection of the actual Attribute objects that correspond to those Ids that I can work with, and 3) attributeEditData is an instance of the IEditData class specific to each given attribute that I'm attempting to bind the posted data from the Edit page to.
Hopefully this additional information clears things up even more.
TryUpdateModel is a generic method, and therefore attempts to infer all type information based on the Generic Type Parameter.
From what I understand in your example above, you are always passing in a IEditData correct?
In effect you are saying:
TryUpdateModel<IEditData>(attributeEditData)
This is most likely the cause for not seeing any properties being set, since IEditData doesn't have any properties ;)
To do what you want you will probably have to create a custom ModelBinder.
As a quick code review side note, your solution seems overly complicated. I had to stare at your solution for a good while just to figure out where to start. Creating a custom model binder may solve your immediate problem, but you might be looking at a big time maintenance headache here. I'm willing to bet there is a simpler approach that will lead to fewer problems down the road.
Based on your comments I have changed the code around from System.Object to your IEditData interface, but everything still holds. I noticed in an earlier comment you mentioned using var because you didn't know the type until runtime. However, there is nothing magic about the var keyword. The only thing it does is give you implicit typing, but it is still statically typed.
The nice thing about MVC is that you can just pop over to Codeplex and have a look at the source for TryUpdateModel if you want. Digging down a few layers you will eventually find a call to this internal method:
protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IDictionary<string, ValueProviderResult> valueProvider) where TModel : class {
if (model == null) {
throw new ArgumentNullException("model");
}
//valueProvider is passed into this internal method by
// referencing the public ControlerBase.ValueProvider property
if (valueProvider == null) {
throw new ArgumentNullException("valueProvider");
}
Predicate<string> propertyFilter = propertyName => BindAttribute.IsPropertyAllowed(propertyName, includeProperties, excludeProperties);
//Binders is an internal property that can be replaced by
// referencing the static class ModelBinders.Binders
IModelBinder binder = Binders.GetBinder(typeof(TModel));
ModelBindingContext bindingContext = new ModelBindingContext() {
Model = model,
ModelName = prefix,
ModelState = ModelState,
ModelType = typeof(TModel),
PropertyFilter = propertyFilter,
ValueProvider = valueProvider
};
binder.BindModel(ControllerContext, bindingContext);
return ModelState.IsValid;
}
Notice the use of typeof(TModel) everywhere... in your case that is getting translated into typeof(IEditData), which isn't very useful since it is only a marker interface. You should be able to adapt this code for your own use, making sure to use GetType() in order to get the actual type at runtime.
I hope this helps out!
P.S. I've added some comments to the above code to help out a little
#Josh, you were very helpful in helping me understand why TryUpdateModel wasn't working for me, and I appreciate that. Unfortunately, I think the larger issue here was that fact that I (not exactly sure which) was either unable or unwilling to try to document all of the details of the requirements for the problem I'm trying to solve here, which I think made it difficult for anyone to be able to provide much meaningful input. The biggest problem for us is that, because we have no idea until runtime which attributes a user has selected for editing, we don't know which objects we'll be working with in the context of these controller actions, or what their types will be. The one place that we safely can work with known data and types, is within the context of each of the unique EditorWorker objects, which is where I've chosen to do the heavy lifting here.
I was hoping and attempting to take advantage of all of the heavy lifting that MSFT has done for us within the MVC framework to handle model binding, but I've come to the conclusion at this point that I don't think that's going to work for us. The solution that I've come up with at this point, is to allow the LoadEditData method of the EditorWorker classes handle loading up the EditData classes for for me. As each EditorWorker class is unique to, and has knowledge of the attribute that it is associated with. The problem I was having originally was that I was letting the EditorWorker.LoadEditData method just return an empty instance of the specific type of EditData class that I needed for the attribute I was currently working with, and let the MVC framework handle model binding to that object for me. That wasn't working because that method is designed to return an object of type IEditData, and I never really knew exactly what type it was that I was currently working with, so I had no way of specifying the type in the call to either of the typed methods: TryUpdateModel<T> or UpdateModel<T>.
So the solution I've come up with, and am going with at least for now (re-education and/or refactoring may very well change this in the future, who knows) is to just pass the Request.Form object into the call to EditorWorker.LoadEditData and let that method handle actually loading up the EditData object that it knows it needs to return for the attribute it's responsible for, which it can do as it knows what information should be in the posted form collection to load up its EditData object.
So that's where I'm at for now. Thanks for the help.
With my understading, the nature of a Action is that properties can be pushed w/ request parameter values. And, one wonderful feature is that Struts2 allows you to directly populate parameter values against Class type property ;)
Assuming there exists a Action and property class as below,
class Action extends ActionSupport {
User user;
#Action(value="hello" {#result=(.......)})
public void execute() {
........
}
.....
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return this.user;
}
}
class User {
String name;
.....
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
you could populate User class property by doing like this.
http://...../hello.action?user.name=John or via jsp page
Then, I realize that there are actually people make an Action property as a Interface type. My question is what is the reason behind this. If there is a sample code demonstrating it will be great.
Thanks in advance!
Sorry, but your question does not make much sense.
To clarify:
"Properties": in Java a "property" of a class is something that is accesible via getter/setters method (setXXX() / getXXX() => property XXX), tipically (but not necessarily) corresponds to a private field.
In Struts2 you have an Action object and typically (not necessarily, not always) the properties are populated (set) from the request (via the "Parameters" interceptor), and later in the view stage read from the JSP (or whatever) page.
So, in your example, for the request http://...../hello.action?user.name=John , Struts2 would try to find in your action (...actually in your value stack) a property "user" which has a property "name", and try to set it (if the types are convertible). That is, he would try to call something like yourAction.getUser().setName("John") . Struts2 does not know -does not care- what type are the properties "User" or "Name", even if they are real fields or not. (They are expected to behaviour as "beans", though: i.e. they should have a default constructor).
Why and when you should code interfaces instead of concrete classes is something that is explained in any Java book, it's just a standard good practice and there are tons of pages about it. It has nothing to do with Struts2. In this context, for an Action, one is tipically only interested in doing so for some "service" fields, objects that are typically long-lived (perhaps singletons), are not instantiated by the action itself (nor by the request!). So, those interfaces are NOT the properties we are considering here, they ( usually ) are not exposed publically and usually are not populated nor read from the client.
I have a simple database from which I am generating Linq2SQL classes using a datacontext. In one part of my application I would like to load the entire relationship such that I get child records. In another part of the application I am passing that relation across the boundary between model and view and I would like to not pass the entire thing since the set of children is pretty large. Is there a way to not have these child classes exported in one section and be exported in another?
I am aware of setting the child property to False in the datacontext but that is a global change.
You can do it with the DataLoadOptions setting on the data context. You'll probably have some sort of builder class somewhere in your application. For the quickest and dirtiest solution, you could do something like the following...
public class SqlContextBuilder
{
public SqlContextBuilder(MyDataContext dataContext)
{
_dataContext = dataContext;
}
private readonly MyDataContext _dataContext;
public MyDataContext CreateEagerLoadingContext()
{
var options = new DataLoadOptions();
// set those options!
_dataContext.LoadOptions = options;
return _dataContext;
}
public MyDataContext CreateLazyLoadingContext()
{
// lazy loading happens by default
return _dataContext;
}
}
One of the solutions is to pass the relation as IQuerable. This will make sure that the relation is not executed until is it required. If you loop over the relation then it will be executed for each child.
Another technique might be to use DTO objects to create a ViewModel of which you like to pass. This means your ViewModel might be very similar to the interface.