I'm trying to build a check list for a ToolStripMenuItem that automatically handles the checking and unchecking of an item and then I provide an event to the programmer allowing them to handle what happens next. If something like this already exists, I would LOVE to know where it is. I've created the collection editor for my custom ToolStripMenuItem and I can add check lists to this collection of checklists. My problem is you create the collection editor like this:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Editor(typeof(ToolStripItemExtCollectionEditor), typeof(UITypeEditor))]
I need to be able to pass this ToolStripMenuItem's DropDownitems to this collection editor so when you add a new checklist and click on the items property of the checklist you can add/remove any one of the known ToolStripMenuItems to/from the checklist. Passing a reference won't work since all of this is happening inside an attribute and I wouldn't know where to begin if the answer is reflection.
This answer applies to VB.NET. I plan on turning this into C# for a DLL, but for now it's in vb.net because that's where I started this idea from and the language the project is in.
Here's what I have so far:
ToolStripMenuItemExt
Purpose: My custom ToolStripMenuItem.
ToolStripMenuItemExt has a CheckListSheet which contains a reference to ToolStripMenuItemExt's DropDownItems (I passed in dropdownitems byref and not byval). It has one property that returns the CheckLists object in CheckListSheet.
CheckListSheet
Purpose: Maintains a reference to the collection I'm observing through an observable collection type and an object of the collection I return in ToolStripMenuItemExt.
CheckListSheet has the CheckLists object. The dropdownitems I pass in byref are stored in an ObservableToolStripItemCollection which hopefully when I get to testing it allows me to update the collection of checklists easier since it inherits ObservableCollection(of ToolStripItemCollection). This class also has a shared function that returns the observable collection which has a scope identifier of private shared.
CheckLists
Purpose: The CollectionBase type that stores CheckList objects.
CheckList
Purpose: Stores the ToolStripItemCollection whose objects act as a single item checked checklist (only one item is checked at a time).
This has some properties for the designer and the collection for the check list. Eventually I'll add in the logic to check and automatically uncheck and raise an event for it.
MenuItemCheckListCollectionEditor
Purpose: Allows a collection of known and instantiated ToolStripItem objects to be displayed and added to a CheckList.
Right now it demands I give it a Type or array of Types so it can establish itself what type of CollectionEditor it is. I haven't be able to show a drop down of types or a drop down of ToolStripItem objects. Any class having ToolStrip in their name inherits ToolStripItem which is why I use this type of object.
If ANYONE has any advice on my current answer or can forecast any foreseeable pitfalls please share. I don't care if you talk in c# or vb.net. Maybe I just need to stop and turn this into c# code. Maybe this is impossible. I am making progress though. What would be extremely helpful is figuring out how MenuStrip's collection editor is able to populate a dropdown of ToolStripItems
[Update]
A collection Editor requires you to provide a type for it to display. This type has to inherit CollectionBase which means at design time there's no way for it to reference the dropdownitems. :sigh:
Related
I have a collection that populates a treeview, and I want to add functionality that allows a node to be added with custom properties. Would the best way to go about it to clone the selected node and then edit the properties from there, or to add a completely new blank node?
The following method is how I'm currently trying to add nodes.
public void add()
{
hClass clone = new hClass();
clone = SelectedNode;
Topics.Add(clone);
}
And then I call the method via a command.
It really depends on what you do with these nodes and which pieces of code an access them. Eric Lippert wrote a blog post focused on immutable collections which might shed more light on your problem.
The collection is a set of references (pointers) to the nodes. If you assign an existing instance of hClass to the collection, a change to the instance will be visible in every place that can access it. If you're using it in a WPF GUI, read about Responding to data source changes
I have a WPF treeview that displays multiple nested classes based on hierarchical datatemplates. It uses the classes here: https://complexdatatemplates.codeplex.com/. This question applies to DataGrids also, though or any control who's selected item is an anonymous class.
What I want to do seems simple. I want to select an item, then press a button and operate directly on the selected item--not the SelectedItem property of the tree view, but the object behind it. But, since the compiler doesn't know the class of the selected item until runtime, it understandably won't give me access to any of the methods or properties in it.
The class in this case is 'Roms', the treeview is 'DB_tree'. I can create a new object from the selected item, and cast it as Roms, then do whatever I want. Like this
roms = (Roms)DB_tree.SelectedItem;
But I can't figure out how to operate on the actual object that would be returned by DB_tree.SelectedItem.
Well, it turns out that by assigning (Roms)DB_tree.SelectedItem to another object
DummyObject = (Roms)DB_tree.SelectedItem
Then everything I do to DummyObject is done to the original object. The equals operator for Objects acts more like assigning an alias than an equals operator.
Strange, that, though clearly common sense to OO programmers everywhere. If the equals operator worked the same way for doubles or ints it would be impossible to do math, now that I understand it, it is cleaning up a lot of my code.
I am new to the MVVM-pattern, and am trying out Caliburn.Micro on a project.
I want to have one ViewModel (which contains a collection of ViewModels) shared by multiple Views, where each view only displays items which have a certain value on one of it's properties.
To get specific, I am using a service which allows me to monitor different values that update frequently. I then get an object of type MonitoredItem, which contains a property of type DataValue, which in turn contains an object for the Value and a property for the value's datatype.
So far I have a MonitoredItemViewModel which uses this service's MonitoredItem class as it's model, and a MonitoredItemsViewModel which contains BindableCollection<MonitoredItemViewModel> MonitoredItems, and commands for adding/removing items.
I also have a MonitoredItemsView where I can see all the items I am currently monitoring.
How do I go about splitting up the view, so that I can have all MonitoredItems where DataValue is an integer/float/double displayed in one area in my window, boolean values displayed somewhere else etc?
Don't do it in the view, instead expose different collections on your ViewModels according to what you need to filter.
This can be done either as known collections, e.g.
public ObservableCollection<MonitoredItemViewModel> ItemsWhereFooIsBar ...
public ObservableCollection<MonitoredItemViewModel> ItemsWhereFooIsntBar ...
or you could do it more generically to return filtered collections on demand
public ObservableCollection<MonitoredItemViewModel> GetItems(Func<DataValue, bool> matches)
{
//Filter collection with
return ... allItems.Where(x=>matches(x))... ;
}
and call via
GetItems(x=>x.Foo == Bar)
The problem you are going to have is when the items change and should switch from collection to collection. If you were using ReactiveUI this would be incredibly easy as you can use Rx to trigger its built in item tracking and also use its .CreateDerivedCollection(...) to build the new collections automatically (hint, hint :-))
If not then you have a few choices.
You can derive a class from ObservableCollection so that as well as being notified via CollectionChanged when new items are added or removed, or also get notified when the properties of the items change as well.
Or you could make your ItemViewModel immutable so that its properties never change, but instead you drop the old item and add an updated one into the correct collection.
I thought I had type editors and converters nailed until I tried to persist a Readonly Reference type property after editing it in a UITypeEditor.
In my UITypeEditor, because I'm working with a read only property, I'm careful to pass back the original value (after updating the relevant sub property).
This change is reflected immediately on the designer but will not be persisted unless I do something like resize the control that the property is attached to.
To fix this I, blindly, include a call to context.OnComponentChanged() before returning the value.
I can see why this is needed. It's a reference type, I've altered it (not replaced it), and the property grid doesn't know this. I have a couple of questions for clarification:
Do I need a call to context.OnComponentChanging as well? A simple call to OnComponentChanged works in the tests I've done so far, but I don't want biting on the arse at some point in the future.
Also, is there any danger that, with my call to OnComponentChanging, I'll be persisting other components, in DesignerTransactions, that I shouldn't be persisting?
(update) ICustomTypeDescriptor works for my Windows Forms app, but not for Silverlight; Not supported. I will keep investigating this idea though and see where i get to.
(/update)
I have, say a few switch panels (for those that like analogies).
Each of these switch panels has switches that have a Name(string) can be in state(bool) of On or Off.
The switchpanel and switches are objects that have INotify interface on them.
Using the switches Names, I create a list of all possible switch names over the collection and create a dynamic class that has all these Names as properties.
SwitchPanel1 (Switches( Switch1 ("Main",On) , Switch2("Slave",Off)))
SwitchPanel2 (Switches( Switch1 ("Bilge",On) , Switch2("Main",Off)))
Produces a collection of
(Main,Bilge,Slave)
And a dynamic class is produced that has the properties:
SwitchPanel : (SwitchPanel)
Main : (Switch)
Bilge : (Switch)
Slave: (Switch)
The idea is that if the switch panel has a switch with the Name of the property, it is placed on that property. So using a bit of linq
propeties["Main"].SetValue(newSwitchType,SwitchPanel.Switches.FirstOrDefault(sw => sw.Name == "Main"));
I want to cast this new dynamic class to INotfyPropertyChanged AND catch the actual changes on these new properties, so if a switch changes state the dynamic object will report it.
Why? It needs to be displayed in a list view and the list view I'm using has its binding by supplying the Property name, and not the binding path.
It also attempts to catch INotify events by casting the object against INotifyPropertyChanged. This means it will sort and/or group when things change.
If you know of a better way to do this let me know. Please.
You probably don't need a dynamic class. You can implement runtime binding properties via ICustomTypeDescriptor / GetProperties(), creating your own PropertyDescriptor implementation that returns the named switch. It isn't clear what knows first about the change, but you could either use INotifyPropertyChanged, or the older property-specific change event, again tied to each property (so each PropertyDescriptor attaches to, for example, the event in the named switch.
Not trivial, but not impossible either.