I applied gesture recognizer on particular UICollectionViewCell. It works fine. But after reloading the uicollectionview, this gesture recongizer is applied rest on collectionviewcell.
Suppose i have 10 cells. I apply gesture recongizer on 1st, 3rd, 4th,6th,7th,9th cells. Rest of cells 2nd,5th,8th cells don't have gesture recognizers. It works perfect on first time. After reload the collection view, 2nd,5th,8th cells also have gesture recognizer but i don't want. How to solve this issue. Please help me.
This is because UICollectionView reuses cells that are not visible any more. (Suppose you have 100 cells and only 8 visible - UICollectionView will keep at least 8 cells initialized, others might be reused) mwthod:
– dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:
Thus, in your method:
- (UICollectionViewCell *)cellForItemAtIndexPath:(NSIndexPath *)indexPath
When you dequeue your cell, you should resetup gesture recognizers or remove if you don't need them
You should always attach your gesture recognizers to the collection view itself—not to a specific cell or view. The UICollectionView class is a descendant of UIScrollView, so attaching your gesture recognizers to the collection view is less likely to interfere with the other gestures that must be tracked. In addition, because the collection view has access to your data source and your layout object, you still have access to all the information you need to manipulate cells and views appropriately.
https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/IncorporatingGestureSupport/IncorporatingGestureSupport.html
Related
I implemented a data virtualization solution using some ideas from CodePlex and the blog of Bea Stollnitz and Vincent Da Ven Berhge's paper (same link). However I needed a different approach so I decided to write my own solution.
I am using a DataGrid to display about a million rows with this solution. I am using UI virtualization as well. My solution is feasible, but I experience some weird behavior in certain situations on how the DataGrid requests data from its source.
About the solution
I ended up writing a list which does all the heavy work. It is a generic class named VirtualList<T>. It implements the ICollectionViewFactory interface, so the collection view creation mechanism can create a VirtualListCollectionView<T> instance to wrap it. This class inherits from ListCollectionView. I did not follow the suggestions to write my own ICollectionView implementation. Inheriting seems to work fine as well.
The VirtualList<T> splits the whole data into pages. It gets the total item count and every time the DataGrid requests for a row via the list indexer it loads the appropriate page or returns it from the cache. The pages are recycled inside and a DispatcherTimer disposes unused pages in idle time.
Data request patterns
The first thing I learned, that VirtualList<T> should implement IList (non generic). Otherwise the ItemsControl will treat it as an IEnumerable and query/enumerate all the rows. This is logical, since the DataGrid is not type safe, so it cannot use the IList<T> interface.
The row with 0 index is frequently asked by the DataGrid. It is seem to be used for visual item measurement (according to the call stack). So, I simply cache this one.
The caching mechanism inside the DataGrid uses a predictable pattern to query the rows it shows. First it asks for the visible rows from top to bottom (two times for every row), then it queries a couple of rows (depending on the size of the visible area) before the visible area (including the first visible row) in a descending order so, from bottom to top. After that it requests for a same amount of rows after the visible rows (including the last visible row) from top to bottom.
If the visible row indexes are 4,5,6. The data request would be: 4,4,5,5,6,6,4,3,2,1,6,7,8,9.
If my page size is properly set, I can serve all these requests from the current and previously loaded page.
If CanSelectMultipleItems is True and the user selects multiple items using the SHIFT button or mouse drag, the DataGrid enumerates all the rows from the beginning of the list to the end of the selection. This enumeration happens via the IEnumerable interface regardless of that IList is implemented or not.
If the selected row is not visible and the current visible area is "far" from the selected row, sometimes DataGrid starts requesting all the items, from the selected row to the end of the visible area. Including all the rows in between which are not even visible. I could not figure out the exact pattern of this behavior. Maybe my implementation is the reason for that.
My questions
I am wondering, why the DataGrid requests for non visible rows, since those rows will be requested again when become visible?
Why is it necessary to request every row two or three times?
Can anyone tell me how to make the DataGrid not to use IEnumerable, except turning off multiple item selection?
I at least found some way to fool the VirtualList. You can read it here.
If you have found another solution (that is even better than mine), please tell me!
I have an application that has a view area. In the view area contains a grid that will contain a collection of controls, such as images, list views, data grids and text.
One one view will be visible at a time, since there is only one view area. Currently when the action is performed to make a new view active I render the view and set it as a child to the view area. Some views takes up to a couple of second to render, so there is a latency here.
I would like to render all 10 views when the application is first loaded and then just grab the appropriate view when called upon. I have not been able to do this. A lot of my view items are usign proportional sizes, the grid uses the Star for the row and column sizes, so it appears that until the view is bound to a visable area where it can calculate all of its sizing it doesn't actual perform any rendering.
For instance, my data grids still flick as it opens it with all of the columns set to 20 width and then it snaps them to the correct widths after. You can visually notice this on the screen, an intial draw with narrow columns and then they all expand to fill the data grid area.
I want to do all rending in the background, then once it is finished display the final product.
A control cannot perform final rendering until it has a container. Maybe try hosting the views differently. Maybe build your views as pages and host the pages in a frame. I don't guarantee that will be faster but something to look at. Could you use tab? I am pretty sure a tabitem reuses the last rendering or at least pieces of the last rendering. Optimize your individual views. A GridView is typically faster than a DataGrid but may not have the features you need. For a table where I need speed I use a GridView and set the column widths based on the data - 100 rows and 40 columns renders in than 1.0 seconds and I put it in a tabitem and if I come back to the tab (after it has rendered once) it renders in 0.1 seconds. If a view has a lot of data that scrolls then try virtualization. Or load multiple frames in the same column / row and only have one visible at at time.
You could try having a separate view area that is the same size as the main one but that is hidden behind the main one, and put all of your 10 views as children of that one so that they render with the appropriate sizes, then swap them out into the main one as necessary...
I need to write an excel-like grid that can have a lot of cells (400x400). All columns have the same width and all rows the same height. Each cell can contain text or be empty and each cell can have a column and/or row span. I suppose this will never work with the Grid panel and I suppose I will need UI virtualization in both column and row direction.
So my first try was to create a virtualizing grid by deriving from VirtualizingPanel and implement IScrollInfo. This could have "easily" be the solution except that I ran into a problem:
To provide IScrollInfo with the relevant information about scroll size and position and to be able to detemine wich items need to be created (realized) next using the ItemsContainerGenerator, I need to know the column index, row indeox and columnspan for each child item (cell). The only way I can think of to do this is using attach properties. The problem is: I can only read the values of attached properties if the ItemContainer that has them is already realized. So I am in a catch 22 here. To know what to realize I need to realize all items. To provide the data for IScrollInfo I need to realize all items.
So it seems that I am at a dead end with this approach.
Do you have any idea how I could implement a control like this or know how I could reslove the above problem?
It strikes me that you may not need to instanciate the UI elements themselves- you can very easily have a collection of DependencyObject-derived viewmodels, each of which has the WidthProperty and HeightProperty set (and possibly bound to the equivalent Width and Height properties of the visible cell UI element, once those are created).
Storing 160,000 (400x400) class instances shouldn't be a problem, especially if you are able to index into the set using row and column.
Here's my scenario. I want to be able to drag and drop elements around in a items collection, and have other elements make way when an item is moved into place... I also want this to be MVVM friendly.
From a high level view it seems to me you should be able to just attach some sort of Interactivity behavior to the items collection that simply gets the layout size of the dragged item, and shuffles elements based on that new layout data, but I'm at a total loss on how to implement something like this.
Other features to consider would be
Auto-scroll on scrollviewer edge during drag operations
Inserted objects may be of variable sizes
It seems to me I'll need to use a FluidMoveBehavior
Look at the project at http://code.google.com/p/gong-wpf-dragdrop/. It can help you solve your problem. The solution is MVVM based on attaching drag&drop behaviours to UI elements and customizing the way how DragXXX events are handled.
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.