If in my wpf application there are multiple grids and a dragable user control.Can anyone suggest code that could return different grid id every time the control is dragged over different grids.
You can use Mouse.DirectlyOver then go up the visual tree to find the first Grid up the tree.
Mouse.DirectlyOver returns the IInputElement that is under the mouse at the time you check the property.
You can walk up the visual tree using a method described in this SO question
Edit: I found the SO question about visual tree walking i was thinking about. (much better than the first link IMHO).
Related
It seems that all of the way of retrieving an element under the Mouse relates to Visual Hit testing.
Is there some mechanism that I'm missing which would allow me to grab the actual UIElement that represents the current visual tree that the HitTest returns?
Summary of what I'm doing:
I have a custom tooltip class which relies on doing something based on the UIElement that the mouse is over.
Simply put, it hooks into the owning Window's PreviewMouseMove event and updates a "current Item". This current item should represent the UIElement that the mouse is currently over top of.
Unfortunately everything I've encountered with Mouse.DirectlyOver, VisualTreeHelper.HitTest (callbacks included) doesn't work.
Can anyone offer insight in how to accomplish a seemingly simple task in WPF within Window's MouseMove event?
Use the Mouse.DirectlyOver property:
var UIElement = Mouse.DirectlyOver as UIElement;
I don't know any explicit way, but the idea is pretty simple,
1) Find the visual tree element
2) Test if the element is present in logical tree,
3) If it's present, you've found the answer.
4) Otherwise you're gonna have to call VisualTreeHelper.GetParent() and continue the algorithm.
Ps, LogicalTreeHelper.GetParent(your visual tree element) MIGHT also work.
I'm having real problems with TreeViews BringIntoView implementation when trying to select things in the tree that are bound via ItemSource and ItemTemplate. It just doesn't work, I've tried pretty much all the fancy ways i could find via google and most don't work and if they do the wrong thing is always selected.
It would be be easier for me if i could just walk the tree one level at a time via treeview items instead of the the things i'd bound in.
Is there a way of "mapping" my bound hierarchical data template items back as treeviewitems?
NOTE: it would appear part of the problem with bring into view is that the items im loading into the tree is done in a "lazy" manner where the children are created until they shown - i have to do it this way as the dataset is huge.
To summarize: I can quickly search through my dataset and ascertain a "nodes" full hierarchical path quite quickly i.e. i can get "root\p1\p2\p3\data" easily enough, but I cant get a treeview thats bound to the dataset to display it using bringintoview. If I could walk the tree using treevitems i could find the node myself and call bringintoview on that. thats the plan anyway.
mucho tacks.
EDIT:
After some more searching I have found this http://blogs.msdn.com/b/wpfsdk/archive/2010/02/23/finding-an-object-treeviewitem.aspx. Which works buts also has problems - I can't initially expand the root object, and I can't work out how to seperate the ItemsPanel and ItemContainerStyle into toplevel styles/resources so i can share them about my other treeviews easily.
I would like to be able to display network-tree information (stored in hierarchical data structure), as in the example shown in here:
In the diagram, I have a number of hosts (top-level nodes) - one of which is considered the 'Master' and therefore rendered differently from the other top-level nodes. Each node can have multiple sub-nodes (probes). The lines between the nodes show connections and if any of the connections goes down, the line changes as shown between Hostname2 and Probe2.3. Any node selected (host or probe) should also be rendered differently.
I am using Prism/MVVM and I'm trying to keep the code as clean as possible, but I'm not sure of the best way forward for displaying this data.
I have considered using a TreeView but I cannot think of a clean way of creating the links between nodes. I also considered creating a custom panel, but I'm not sure that's the most appropriate and wouldn't know where to start. Then I thought of creating a custom ItemsControl, as it would be nice to use the DataTemplate and HierarchicalDataTemplate. I could also create a UserControl that contains a canvas and do everything in the code-behind there but it doesn't feel the best way.
I'd be grateful for opinions, example code, links or any suggestions you may have.
You're in luck, last year I had to write something very similar for my current job. I can't give you any of my code but I can lead you in the proper direction.
I found a directed graph collection class available here: http://msdn.microsoft.com/en-us/library/ms379574(v=vs.80).aspx#datastructures20_5_topic3.
I also use a Radial Panel I found on MSDN: http://msdn.microsoft.com/en-us/library/ms771363(v=VS.90).aspx. This allows multiple nodes to draw in a geometric shape. So if you have 3 nodes, they draw a triangle, 4 a square, 5 a pentagon, etc...The more nodes you have, the more the layout becomes a circle. This wouldn't work for you, but if you follow the link it shows you how to create a custom panel with a custom layout. It could be beneficial.
I then used a Canvas as the stage, with the RadialPanel as the Canvas' child element. Each node is just a WPF UserControl with an ellipses background that is added to the RadialPanel. The directed graph collection then become a collection of node view models. I store where the node is connecting, almost like a linked list. This allows me to traverse my graph collection easily without having to iterate each node to find the nodes I'm looking for.
There are some tricks involved in drawing to ensure the layout is proper, especially when drawing your connecting lines. See this StackOverflow post I made: WPF and C# - Issue with GeneralTransform and UIElement.TransformToVisual. It has a link to an image of my node graph so you can compare our graphs.
This obviously isn't everything, but I think it's a good start. For me, I couldn't really override any current controls to do exactly what I needed, so I went the hard way. The trade off is a lot of work in the code-behind and view models, but I also control the major aspects of how it's drawn. I this helps.
We have a WPF application (.Net 4.0) using a Docking Control (Actipro). We can dock out the docking windows. In that case, a "real" Window is created and the content is assigned to that window.
Of course, moving stuff in the Visual Tree will re-trigger the complete layouting. This is problematic, because in one of these docking windows, we have a diagramming control (Mindfusion Diagramming,WPF control) that can take up to 10 seconds to completely layout itself (very large diagrams).
I don't think that there's any direct solution to this problem. I wonder however how other programmers with similar issues approached this problem. Is there any clever way to avoid recalculating the layout?
In theory, nothing really changes since the diagram is inside a ScrollViewer, so whenever it is placed, the amount of avaiable space remains the same(infinite).
Edit: Also note that the diagram control inside is interactive. We need Drag&Drop.
Here is an idea.
Create a custom class inheriting from Decorator.
Wrap your diagramming control inside the decorator.
Override MeasureOverride and simply call base.Measure but store the result in a field before returning.
Add a property which enables you to disable the measure call. If the property is true simply return the previous size in MeasureOverride instead of calling base.Measure.
Set the property while changing the visual hierarchy.
From the top of my head I can't think of any reason why this shouldn't work.
I have actually done something very similar not too long ago. When implementing the sliding animation for the side panels in NovaMind I used a Decorator to prevent the content from performing layout while the panel animates its width. I calculated the size with the final width, stored it and then used MeasureOverride to fake the current size... This prevented the performance issues involved when trying to animate the width of a complex control. :)
Another possibility is that the problem isn't related to layout so much as the "severing" of the visual tree when moving the content from one window to another. This seems to cause a slew of recalculations for dependency properties, which if your visual tree for content was like mine, upwards of 2000 controls, it was really slow.
I couldn't find an elegant solution to this using Actipro docking library itself, so I thought how I could divert WPF from doing this behavior. The solution I came up with was to create my content as a single WinFormsHost control with a single child of a WinForms UserControl. Then, I made that WinForms UserControl have it's content be the WPF based content that should appear as the docking window content. I figured that when WPF started walking the visual tree from the top to re-evaluate all dependency properties when the tree was "snipped", it would run into the WinForms control and stop.
My Actipro docking tool windows used to take 6 seconds or so just to switch tabs or to float. Now they are essentially instaneous. You have to ensure that any command handlers are not at the application level, but instead at your WPF content level and you might have to finagle wtih the location of some style files, but it worked fantastic.
you might want to replace your diagramming control in the visual tree with an Image, render the diagram offscreen and use rendertargetbitmap to convert the rendered diagram to an image, which you can use as the source for the Image in the visual tree.
something like this:
// image is the Image from the visual tree
int h = image.ActualHeight;
int w = image.ActualWidth;
// layout the diagram to the size of the image
diagram.Measure(new Size(w, h));
diagram.Arrange(new Rect(newSize(w,h)));
diagram.UpdateLayout();
// render the diagram to a bitmap
RenderTargetBitmap bmp = new RenderTargetBitmap((int)w, (int)h, 96, 96, PixelFormats.Default);
bmp.Render(diagram);
// set the source of your image to the bitmap
image.Source = bmp;
in the example if PixelFormats.Default doesn't seem to work, you might try PixelFormats.Pbgra32, which I think is a more common format to use in this type of thing.
you might also be able to use a VisualBrush in a similar manner. I can imagine in the long run you could probably create a wrapper class for the diagram to automatically display the image copy and re-layout the diagram only if something changes (ie a part of the diagram or the size).
I have such situation - I'd like to build timeline control. So I have UserControl and ItemsControl on it (every row represents some person). The ItemsControl contains another ItemsControl as ItemsControl.ItemTemplate - it shows e.g. events for the person arranged by event's date.
So it looks as some kind of grid with dates as a column headers and e.g. peoples as row headers.
........................|.2010.01.01.....2010.01.02.....2010.01.03
Adam Smith....|......[some event#1].....[some event#2]......
John Dow.......|...[some event#3].....[some event#4].........
I can have a lot of persons (ItemsControl #1 - 100-200 items) and a lot of events occured by some day (1-10-30 events per person in one day)
the problem is that when user scrolls ItemsControl #1/#2 it happened toooo sloooooowwww due to a lot of elements should be rendered in one time (as I have e.g. a bit of text boxes and other elements in description of particular event)
Question #1 - how can I improve it? May be somebody knows better way to build such user control? I have to mention that I'm using custom Virtual panel, based on some custom Virtual panel implementation found somewhere in internet...
Question #2 - I'd like to make image with help of WriteableBitmap and render data bound control to image and to show image instead of a lot of elements. Problem is that I'm trying to render invisible data bound control (created in code behind) and it has actualWidth/Height equals to zero (so nothing rendered) even if I'm using Dispatcher.BeginInvoke(() => {...} approach. How can I solve it?
Thank you very much for you help!
About question #1: Nested ItemsControl virtualization is tricky. The problem is that even if the outermost control supports virtualization, the inner controls are measured with infinite length and thus instantiate all of their children. Instead of hosting an ItemsControl inside another, merge all data to the same list, using styling to simulate the hierarchy. Alternatively, find a commercial datagrid control that supports nested virtualization.