I'm writing a Windows application and using a Listbox control. I'm developing with Visual Studio C# 2008 Express Edition.
I've got a data object that looks something like this
public class RootObject
{
public List<SubObject> MySubObjects{ get; set;}
}
I've got a ListBox on my form, and also a property "MyRootObject" which, obviously, holds a RootObject. When the control is initialized, I set:
_listBox.DataSource = MyRootObject.MySubObjects;
Now, when the form loads, I debug and see that the DataSource is being set correctly. But nothing is displayed. I've overridden SubObject's ToString() method and it's not even being called. I tried setting _listBox.DisplayMember to a property of SubObject just to see if there was some problem there, but still nothing. I tried calling _listBox.Update() and _listBox.Refresh() after setting the DataSource, but still no love. The DataSource has all the data... it's just refusing to display it.
So while debugging, I wondered WTF and I decided to just do
_listBox.DataSource = new List<SubObject>{ new SubObject(), new SubObject() };
Sure enough, this worked, and I see two things listed in my listbox.
So then, really curious, I decided to try copying the list of objects and putting that in the listbox, like so:
_listBox.DataSource = MyRootObject.MySubObjects.ToArray();
This works! And it's a workaround to my problem for now... but a very annoying one. Does anyone know why I need to basically copy the list of objects like this to get it to work, rather than just setting the _listBox.DataSource = MyRootObject.MySubObjects; ? Again, the DataSource has all the right data either way after setting it... it's just when it's copied data, it actually displays, and when it's not, it's not displayed.
((CurrencyManager)_listBox.BindingContext[_listBox.DataSource]).Refresh();
Sux0r I know, but this works.
(originally found answer here)
Off the top of my head, this is because the ListBox.DataSource property must contain something that implements the IList interface. Your generic List<SubObject> does not implement IList; it implements IList<T> (in the System.Collections.Generic namespace). Array objects, on the other hand do inherit from IList, so handing the data in via that kind of object works.
You could try pulling an Enumerator (which also implements IList) out of your List<SubObject> object and plug that in. If it works, then the issue I've described is your problem. If it doesn't, then I'm talking out of my hat.
If this is indeed the issue, I am surprised that shoving in an unsupported object doesn't throw an exception.
so far that i know, whenever you want to set a collection to a
[ComboBox,ListBox].DataSource
you have to set the DisplayMember and ValueMember. DisplayMember and ValueMember are filled with the property name of the Class in the collection that is assigned to the listbox/combobox. Ex.
//Populate the data
RootObject root = new RootObject();
root.MySubObjects.Add(new SubObject("1", "data 1"));
root.MySubObjects.Add(new SubObject("2", "data 2"));
//Assign data to the data source
_listBox.DisplayMember = "DisplayProperty";
_listBox.ValueMember = "ValueProperty";
_listBox.DataSource = root.MySubObjects;
root.MySubObjects returns List of SubObject, and SubObject has to have properties called DisplayProperty and ValueProperty, ex.
public class RootObject
{
public List<SubObject> MySubObjects { get; set; }
}
public class SubObject
{
public string ValueProperty { get; set; }
public string DisplayProperty { get; set; }
}
I think you have to call Bind method after assigning to the list box data source
something like _listBox.DataSource.bind()
and you will have your listbox disappeared
you could try and use a BindingSource
( http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.aspx )
inbetween the Listbox and your collection. Bindingsources handles a bunch of stuff and also includes Suspend/ResumeBinding properies that can be useful when updating the list
you could also try out wpf as its databinding is far superior to that of winforms :) but maybe thats not possible in your case
I believe you need to call _listbox.DataBind(); after assigning the datasource.
However, I've never used a property as a datasource before, I've only used methods. Have you tried changing your property to a method to see if that's the problem?
You could try
_listBox.DataSource = new BindingList<SubObject> (MyRootObject.MySubObjects);
instead. BindingList implements some more interfaces than List, which are essential for DataBinding.
I have a special rule for problems like this that I always try to remember before wasting an entire day hammering on it (believe me, I've spent many days hammering!). The rule is: when system behavior is really strange, the underlying cause must be very stupid. As intelligent programmers, we have a tendancy to search for esoteric causes or bugs in framework code to explain our problems. Sometimes the answer is that we were in a hurry and made a careless mistake that we haven't yet caught.
To quote Sherlock Holmes, "when you've removed the impossible, then whatever remains, no matter how improbable, must be the truth". In this case, the improbable truth is that the MySubObjects property of MyRoot object is null.
Related
I have a collection mapped in my model:
public class Project
{
// ...
public virtual ICollection<ProjectSupplier> ProjectSuppliers {get; set;}
}
And I want to retrieve original value of ProjectSuppliers collection (I know for sure that it has been loaded). I tried:
var originalProjectSuppliers = _context.Entry(project)
.OriginalValues
.GetValue<ICollection<ProjectSupplier>>("ProjectSuppliers");
But it gives me error:
System.ArgumentException : The 'ProjectSuppliers' property does not exist or is not mapped for the type 'Project'
I also tried getting DbCollectionEntry like that:
_context.Entry(project).Collection(p => p.ProjectSuppliers)
But it doesn't contain OriginalValues, only current ones.
Apparently this is the only way. Not what I would have hoped either, but the answer is written by a guy who works on Entity Framework, so I guess he would know.
UPDATE
Based on the linked answer above, I've built something perhaps more in line with your actual question, or at least you can use it to get back the original collection. I'm not sure it's the best way though, so I posted my own question on how to do it better.
I'm sure there's something I'm missing here, but a lot of Googling hasn't uncovered it for me. The situation is like this:
We created a custom workflow designer that allows end users to build workflow definitions from various custom activities we define (Review, Submit, Notify, etc). These definitions (Xaml) get saved off to a Db and used to create workflow instances for long running processes in our system. The users can set properties on each of them (e.g. Review has a property argument: AllowedRoles). The problem is, I'm not able to pass those properties on to nested activities.
For example:
Review has an internal activity 'WriteStatus' that needs access to the 'AllowedRoles' property on Review. If 'AllowedRoles' is defined as a Property, WriteStatus can't "see" it to assign it's value. I can change it from a Property to an InArgument, but then I'm not able to map values to and from the property in the designer (these properties should be part of the definition, and not associated with any specific context).
Has anyone faced this issue or have advice on how I could approach the problem differently?
Thanks in advance!
Royce
I was able to get around the property vs InOurArgument problem by converting the XAML activities to code. This allowed me to set the properties on activities in code, and then pass them to inner activities inline. There may be a better way, but it's working out well so far.
public sealed class Test : Activity
{
public string Stuff { get; set; } // CLR Property
public Test()
{
Implementation = () => new WriteLine {Text = Stuff};
}
}
I've been looking around for an answer to this, which I can't believe hasn't been asked before, but with no luck I'm attempting here.
I have a signup form which differs slightly based upon what type of participant the requester is. While writing tests for the solution, I realized that all actions did the same things, so I'm attempting to combine the actions into one using a strategy pattern.
public abstract class BaseForm { common properties and methods }
public class Form1 : BaseForm { unique properties and overrides }
....
public class FormX : BaseForm { unique properties and overrides... in all about 5 forms }
Here is the combined action:
[ModelStateToTempData, HttpPost]
public ActionResult Signup(int id, FormCollection collection)
{
uiWrapper= this.uiWrapperCollection.SingleOrDefault(w => w.CanHandle(collection));
// nullcheck on uiWrapper, redirect if null
var /*BaseForm*/ form = uiWrapper.GetForm(); // Returns FormX corresponding to collection.
this.TryUpdateModel(form, collection.ToValueProvider()); // Here is the problem
form.Validate(this.ModelState); // Multi-Property validation unique to some forms.
if (!this.ModelState.IsValid)
return this.RedirectToAction(c => c.Signup(id));
this.Logic.Save(form.ToDomainClass());
return this.RedirectToAction(c => c.SignupComplete());
}
The problem I'm having is that TryUpdateModel binds only the common properties found in BaseForm. My previous code used public ActionResult FormName(int id, FormX form) which bound properly. However, I did some testing and discovered that if I replace var form with FormX form the form binds and everything works, but I'm back to one action per form type.
I'm hoping to find a way to get this to bind properly. form.GetType() returns the proper non-base class of the form, but I'm not sure of how to grab the constructor, instantiate a class, and then throw that into TryUpdateModel. I know that the other possibility is a custom ModelBinder, but I don't see a way of creating one without running into the same FormBase problem.
Any ideas or suggestions of where to look?
I was trying to do something similar to Linq, I was trying to create a class that would inherit some standard fields (ID, etc). I found that the default Linq engine would only use fields from the instantiated class, not from any inherited classes or interfaces.
To construct a Type simply use code like:
var form = Activator.CreateInstance(uiWrapper.GetForm());
I figured it out!
Erik's answer wasn't the solution, but for some reason it made me think of the solution.
What I really want form to be is a dynamic type. If I change this line:
dynamic form = uiWrapper.GetForm();
Everything works :)
On top of that, logic.Save(form.ToDomainClass()) also goes directly to Save(DomainTypeOfForm) rather than Save(BaseDomainForm) so I can avoid the headache there as well. I knew that once I figured out the problem here I could apply the answer in my logic class as well.
I'm working with a database where the designers decided to mark every table with a IsHistorical bit column. There is no consideration for proper modeling and there is no way I can change the schema.
This is causing some friction when developing CRUD screens that interact with navigation properties. I cannot simply take a Product and then edit its EntityCollection I have to manually write IsHistorical checks all over the place and its driving me mad.
Additions are also horrible because so far I've written all manual checks to see if an addition is just soft deleted so instead of adding a duplicate entity I can just toggle IsHistoric.
The three options I've considered are:
Modifying the t4 templates to include IsHistorical checks and synchronization.
Intercept deletions and additions in the ObjectContext, toggle the IsHistorical column, and then synch the object state.
Subscribe to the AssociationChanged event and toggle the IsHistorical column there.
Does anybody have any experience with this or could recommend the most painless approach?
Note: Yes, I know, this is bad modeling. I've read the same articles about soft deletes that you have. It stinks I have to deal with this requirement but I do. I just want the most painless method of dealing with soft deletes without writing the same code for every navigation property in my database.
Note #2 LukeLed's answer is technically correct although forces you into a really bad poor mans ORM, graph-less, pattern. The problem lies in the fact that now I'm required to rip out all the "deleted" objects from the graph and then call the Delete method over each one. Thats not really going to save me that much manual ceremonial coding. Instead of writing manual IsHistoric checks now I'm gathering deleted objects and looping through them.
I am using generic repository in my code. You could do it like:
public class Repository<T> : IRepository<T> where T : EntityObject
{
public void Delete(T obj)
{
if (obj is ISoftDelete)
((ISoftDelete)obj).IsHistorical = true
else
_ctx.DeleteObject(obj);
}
Your List() method would filter by IsHistorical too.
EDIT:
ISoftDelete interface:
public interface ISoftDelete
{
bool IsHistorical { get; set; }
}
Entity classes can be easily marked as ISoftDelete, because they are partial. Partial class definition needs to be added in separate file:
public partial class MyClass : EntityObject, ISoftDelete
{
}
As I'm sure you're aware, there is not going to be a great solution to this problem when you cannot modify the schema. Given that you don't like the Repository option (though, I wonder if you're not being just a bit hasty to dismiss it), here's the best I can come up with:
Handle ObjectContext.SavingChanges
When that event fires, trawl through the ObjectStateManager looking for objects in the deleted state. If they have an IsHistorical property, set that, and changed the state of the object to modified.
This could get tricky when it comes to associations/relationships, but I think it more or less does what you want.
I use the repository pattern also with similar code to LukLed's, but I use reflection to see if the IsHistorical property is there (since it's an agreed upon naming convention):
public class Repository<TEntityModel> where TEntityModel : EntityObject, new()
{
public void Delete(TEntityModel entity)
{
// see if the object has an "IsHistorical" flag
if (typeof(TEntityModel).GetProperty("IsHistorical") != null);
{
// perform soft delete
var historicalProperty = entity.GetType().GetProperty("IsHistorical");
historicalProperty.SetValue(entity, true, null);
}
else
{
// perform real delete
EntityContext.DeleteObject(entity);
}
EntityContext.SaveChanges();
}
}
Usage is then simply:
using (var fubarRepository = new Repository<Fubar>)
{
fubarRepository.Delete(someFubar);
}
Of course, in practice, you extend this to allow deletes by passing PK instead of an instantiated entity, etc.
I want to handle different types of docs the same way in my application
Therefore:
I have a generic interface like this.
public interface IDocHandler<T>where T: class
{
T Document { get;set;}
void Load(T doc);
void Load(string PathToDoc);
void Execute();
void Execute(T doc);
}
And for different types of documents I implement this interface.
for example:
public class FinanceDocumentProcessor:IDocumentHandler<ReportDocument>
{}
public class MarketingDocumentProcessor:IDocumentHandler<MediaDocument>
{}
Then I can do of course something like this:
IDocumentHandler<ReportDocument> docProc= new FinanceDocumentProcessor();
It would be interessting to know how I could inject T at runtime to make the line above loosly coupled...
IDocumentHandler<ReportDocument> docProc = container.resolve("FinanceDocumentProcessor());
but I want to decide per Configuration wether I want to have my FinanceDomcumentProcessor or my MarketingDocumentProcessor... therefore I would have to inject T on the left site, too ...
Since I have to use c# 2.0 I can not use the magic word "var" which would help a lot in this case... but how can I design this to be open and flexible...
Sorry for the misunderstanding and thanks for all the comments but I have another example for my challenge (maybe I am using the wrong design for that) ...
But I give it a try: Same situation but different Explanation
Example Image I have:
ReportingService, Crystal, ListAndLabel
Three different Reporting Document types. I have a generic Handler IReportHandler<T> (would be the same as above) this Handler provides all the functionality for handling a report Document.
for Example
ChrystalReportHandler:IReportHandler<CrystalReportDocument>
Now I want to use a Framework like Unity (or some else framework) for dependency injection to decide via configuration whether I want to use Crystal, Reportingservices or List and Label.
When I specify my mapping I can inject my ChrystalReportHandler but how can I inject T on the left side or in better word The Type of ReportDocument.
IReportHandler<T (this needs also to be injected)> = IOContainer.Resolve(MyMappedType here)
my Problem is the left Site of course because it is coupled to the type but I have my mapping ... would it be possible to generate a object based on Mapping and assign the mapped type ? or basically inject T on the left side, too?
Or is this approach not suitable for this situation.
I think that with your current design, you are creating a "dependency" between IDocumentHandler and a specific Document (ReportDocument or MediaDocument) and so if you want to use IDocumentHandler<ReportDocument or MediaDocument> directly in your code you must assume that your container will give you just that. The container shouldn't be responsible for resolving the document type in this case.
Would you consider changing your design like this?
public interface IDocumentHandler
{
IDocument Document { get; set; }
void Load(IDocument doc);
void Load(string PathToDoc);
void Execute();
void Execute(IDocument doc);
}
public class IDocument { }
public class ReportDocument : IDocument { }
public class MediaDocument : IDocument { }
public class FinanceDocumentProcessor : IDocumentHandler { }
public class MarketingDocumentProcessor : IDocumentHandler { }
If I understand you correctly, you have two options.
if you have interface IDocHandler and multiple classes implementing it, you have to register each type explicitly, like this:
container.AddComponent>(typeof(FooHandler));
if you have one class DocHandler you can register with component using open generic type
container.AddComponent(typeof(IDocHandler<>), typeof(DocHandler<>));
then each time you resolve IDocHandler you will get an instance of DocHandler and when you resolve IDocHandler you'll get DocHandler
hope that helps
You need to use a non-generic interface on the left side.
Try:
public interface IDocumentHandler { }
public interface IDocumentHandler<T> : IDocumentHandler { }
This will create two interfaces. Put everything common, non-T-specific into the base interface, and everything else in the generic one.
Since the code that you want to resolve an object into, that you don't know the type of processor for, you couldn't call any of the T-specific code there anyway, so you wouldn't lose anything by using the non-generic interface.
Edit: I notice my answer has been downvoted. It would be nice if people downvoting things would leave a comment why they did so. I don't care about the reputation point, that's just minor noise at this point, but if there is something seriously wrong with the answer, then I'd like to know so that I can either delete the answer (if it's way off target) or correct it.
Now in this case I suspect that either the original questionee has downvoted it, and thus either haven't posted enough information, so that he's actually asking about something other than what he's asked about, or he didn't quite understand my answer, which is understandable since it was a bit short, or that someone who didn't understand it downvoted it, again for the same reason.
Now, to elaborate.
You can't inject anything "on the left side". That's not possible. That code have to compile, be correct, and be 100% "there" at compile-time. You can't say "we'll tell you what T is at runtime" for that part. It just isn't possible.
So the only thing you're left with is to remove the T altogether. Make the code that uses the dependency not depend on T, at all. Or, at the very least, use reflection to discover what T is and do things based on that knowledge.
That's all you can do. You can't make the code on the left side change itself depending on what you return from a method on the right side.
It isn't possible.
Hence my answer.