I have a treeview that displays a few nodes, say 5 or so. When the final node is selected, I want to display records belonging to that final node (linked via a foreign key) inside of a listbox.
So the structure would be
Treeview Listbox
-1 -Object belonging to 5
--2 -Object belonging to 5
---3
----4
-----5
My question is if such a comperation between these two controls is even possible and if I'm going about it the smartest way.
I can't find anything about it (getting actual data from the last selected node in the treeview is already pretty hard on how to find a how to). Any tips in the right direction would be very appreciated.
It is possible to do this exactly the way you're trying to by using attached properties, but it's a bit of a clumsy way of going about it. What you really should be doing is using data binding.
Your TreeView is, presumably, bound to some kind of data structure in your view model (data context), and what class that is should (again, presumably) be able to easily ascertain whether or not a particular given item is the deepest/last one in the tree. So create a property in that class and bind the TreeView's SelectedItem to that, so that it gets updated whenever the user selects an item in the Tree. Next, create another property for your ListBox to bind to. When your first property gets set, it either sets this second property to the currently selected item if it's the last in the list, or sets it to null if it isn't.
By doing this you de-couple your logic from your view and you make something that's much easier to debug, test and modify in future.
Related
I have an ObservableCollection that is wrapped by a ListCollectionView.
The ListCollectionView is displayed in a grid (XamDataGrid).
When I add items to my observable collection those items are exposed by the ListViewCollection sorted in the order defined by the SortDescriptions property.
Here's the problem. I would like new items to appear at the bottom of my grid even though the existing ones are currently sorted. Next time the user sorts (by clicking at the column header) the new items should be sorted.
I'm struggling to find a solution to this problem. Anyone's had a similar issue?
Solution A: Manage the sorting yourself behind the scenes
Easiest thing to do here is sort the data behind the scenes (you can use LINQ for that), then assign it to the grid without the sort descriptions. Then as you add items, they'll just appear at the end of the collection. When you click on a header, intercept that and sort yourself accordingly.
Solution B: Add another SortDescription
Another approach is to add another property to your data and create a primary sort on that field first, then by what you actually want to sort on. For instance, you could add a boolean called existedBeforeSort. If you can't modify your model, you can do it via an extension where you store the actual value in a dictionary keyed on the object itself. (That's sort of how DependencyProperties work, but this can be for any object since you're managing the storage.)
Now, in the grid, as you click a sort header, the first thing you do is set the existedBeforeSort property on all items to true. Since your first SortDescription is based on that field, followed by the sort descriptions generated by clicking on the headers, all newly added items will appear at the bottom as you wanted.
The trick to this second approach is making sure as you click on sort headers, you manually make sure your SortDescription based on your existedBeforeSort property is always inserted first. In essence, you're hijacking the implied SortDescriptions and injecting yours to supersede theirs. Shouldn't be too difficult though.
Hope this helps!
I have a very complex databinding I want to accomplish here using the below:
2 SQL CE tables named mainTable and secondaryTable
1 Fluidkit ElementFlow control named myElmntFlow
2 UserControls named myUsrCtrl and otherUsrCtrl
All of the above are already created and implemented but the UserControls are populated into the myElmntFlow control's items list programmatically through lenghty backgroundworker code that does take a good bit of time to run when the number of items to enter is > 20.
This is how they get created as of now:
The backgroundworker loops through each row of mainTable and adds the myUsrCtrl control to the list of items in myElmntFlow if the value of the row in column "Selected" = "'Yes'".
Then, it modifies the content of the newly added myUsrCtrl as such: it adds a otherUsrCtrl into the myUsrCtrl's stackpanel (named stckPanel) for each row in secondaryTable where the value of the column "FullName " = the value of the same column of the mainTable row we used to created the myUsrCtrl control.
And then populates the otherUsrCtrl's sevaral labels with the value of the secondaryTable row looked at at the moment.
Very confusing but it is a complex scenario. Let's use an example:
In mainTable, the row #4 has the FullName value of "Chad Jones" and
also has the Selected value of "Yes".
A new instance of the myUsrCtrl control is added to the
myElmntFlow's list of items as such:
myElmntFlow.Items.Add(myUsrCtrl);
The newly added myUsrCtrl control has a stackpanel (stckPanel)
We filter the secondaryTable where the FullName = "Chad Jones"
For each row in the now filtered secondaryTable, we add a new
instance of otherUsrCtrl to the previously created myUsrCtrl's
stckPanel control
The different labels in the otherUsrCtrl are populated with the values of the
row in secondaryTable
Can this possibly be converted into a DataBinding within the XAML of the controls as I want to implement several features later on (such as a nice SearchBox with autocomplete) that would be quite poor if they were to be coded behind by writing hundreds of line to tell which data to filter, sort , take , compare etc...
I wrote this as clearly as I could, just hope it's understandable.
PS: I would like to keep my SQL structure as the data is going to become quite consequent over time and I believe that the SQL is the way to go when manipulating thousands of lines.
It's not a very confusing scenario, it's just made confusing by the complex handling that goes on there. It can indeed be made much easier using bindings and MVVM (Model-View-ViewModel) so please take some time to read about the basics of that. There are a ton of tutorials and introductory materials on the web, a simple search will give you more than enough to go on.
When you're comfortable with the concepts, all you need is to transform the data into a sequence of objects (no matter how you go about it), then use an ItemsControl to represent the UI for a list of items. Use DataTemplates to specify how each item should be displayed, binding elements in the DataTemplate to the properties of each item. These things can be nested so you can have ItemsControls in your DataTemplates which use other DataTemplates etc.
In order to represent a collection of items bound to an ItemsControl look at using an ICollectionView which will help tremendously with filtering/sorting/etc.
Sorry about the very broad strokes but it is a pretty broad question. If you need more specific help I'll gladly add more.
So it seems like what I want to do should be straightforward, but I haven't been able to find a way to do it...
I need to display a list of objects that represent custom elements for entering data. Exactly how each object is displayed depends on the parameters of the object - so it could be a grid containing a name, description, and text box. It could be a grid with a couple labels and a dropdown. It could be an expander that contains multiple sub-objects. It could be something new that hasn't been built yet (so it needs to be extensible). Right now, I am populating this list by creating the FrameworkElement for each object and then adding it to a Grid by hand.
I would like to switch to keeping my objects in an ObservableCollection, and then binding that collection to a ListBox (or similar). That way, when new objects are added or removed from the list, the UI would automatically update itself accordingly. What I can't figure out is, is there a way to point it to my C# method for creating the custom-configured FrameworkElement for each object, so that when new objects are added the appropriate elements will be added to the UI?
Well, you're on the right track as far as wanting to use an ObservableCollection<T> and a ListBox control. Though, I'd venture to say you might want to simply use an ItemsControl since you probably don't care about selecting a particular item, but merely displaying an enumeration of items, and the ListBox would allow you to actually select one of those items.
Your problem is that you want each item in the list to display differently depending on certain criteria. For this you'll want to look at the DataTemplate and DataTemplateSelector classes.
Basically, a DataTemplate is a way of saying "I want my item to look like this.", and a DataTemplateSelector is a way of saying "I want to select this specific DataTemplate based on this criteria."
Here are a few examples on how to use the DataTemplate/DataTemplateSelector classes:
http://tech.pro/tutorial/807/wpf-tutorial-how-to-use-a-datatemplateselector
http://mikestedman.blogspot.com/2009/04/datatemplateselector.html
http://wpftutorial.net/DataTemplates.html
Seperating the presentation from the model is always a good idea. It seems like you are on the right track.
Foreach object type, you should create a DataTemplate and then use ItemTemplateSelector to select the correct template for each object type.
Good luck
I have a small gui with a listbox. The listbox is bound to a collection. The user can edit an item in the collection using an "Edit" window.
The Edit window is bound to the selected object in the listbox. One of the validations I need to perform is to make sure the user does not enter a name for an item which has already been used (meaning it can't be used by any of the other objects in the listbox).
Is there a good way to do this with WPF validation?
The item you are validating must provide reference to a parent object (collection).
When you have parent collection, the rest is simple, and I think, got nothing to do with WPF.
Take a look at the Enforcing parent-child relationship in C# and .Net
I Have Treeview (shown as above) in my app, I have binded it with collection...
now the problem is whenever I expand on Colorodo by default Aspen should get selected, means whenever I expand first item that Node should get selected..
Any Ideas/suggestion Please
Unfortunately, as I'm sure you have discovered, is that you cannot set the treeViewInstance.SelectedItem property as it's read-only.
From memory, each TreeViewItem has a IsSelected property that you can set. You try to listen for expand/collapse on the items and maybe set this property. Without trying this myself I don't know if it is a) a good solution b) if it would even works.
To get the TreeViewItem that is the container for the item in collection use
treeViewInstance.ItemContainerGenerator.ContainerFromItem(yourDataItem) as TreeViewItem;
Another idea (the way I would do it) is to use a ListBox/ListView and fake the hierarchical view. The create a view model controller and item, wrap your data, and manage this all yourself. If you want more information, please leave a comment and I will dig up a few examples to help.
HTH,
Dennis
There are two apporches choose what ever you like.
i) explore ItemTemplageSelector, not sure but may be possible to do work with it.
Other wise on tree expand event or mouse capture event get the Current Root node and then select its first child with index like rootNode.child[0]... set this is as Selected True or Isfocused and perfom operation that is intended on its click you you will make user feel like it is selected.