Ultimately, my aim is to have a grid (by grid I mean rows and columns, however it's achieved) of small stack panels to represent time intervals throughout a day. Not too disimilar from the following I suppose (simple calendar-type layout on the right):
(source: msdn.com)
I need a way of creating this grid dynamically and naming the panels appropriately for whenever an event is fired (to be specific - a drop event, each panel's drop event will be wired to the same method in which I must distinguish what panel (i.e. at what point in the day, and on what row) the item was dropped on).
Thanks a LOT for any help!
Dan
You probably won't get the full code to do that from here, but I can point you in the right direction.
You are probably going to want to use nested ItemsControl. I have done something like this in the past where my outer ItemsControl for the Calendar was a Grid, and grid cell contained an inner ItemsControl with a StackPanel of TaskItems.
The most important part is getting your data layer right. I used CalendarDayModel classes, which had a Date property and an ObservableCollection<TaskModel> list. It also had Commands to handle user events, such as double-click events.
My outer ItemsControl was bound to the ObservableCollection<CalendarDayModel> and the inner ItemsControl were bound to the ObservableCollection<TaskModel>
I have some examples of an ItemsControl here, but take note of the last example that uses a Grid.
Related
I have a StackPanel of Datagrids that contain data about various things. A user should be able to click on one of those datagrids and that datagrid should expand and take the place of the four datagrids on the screen. Clicking on the expanded grid should return the screen back to the previous display of four data grids.
I have tried replacing the top grid in the backend (I don't think this is a violation of MVVM since it is dealing purely with the display, but I could be wrong) with the selected grid, which doesn't seem to work. I have also tried hiding the grids to see if that would work. I found several topics here and elsewhere talking about moving columns and/or rows around at runtime, but nothing about moving an entire datagrid at runtime.
I would suggest building your UI view as a grid with column/row sizes bound to match their content, and use a backend property to determine whether the various datagrids should be Visible or Collapsed as a result of your clicking. Then the UI will adapt to fit the scenario you want.
Another alternative is to have a couple of views which have the explicit arrangement of controls you want, then have an outer ContentControl whose Content property is changed to one or the other as a result of the clicks.
I'd favour the former though for simplicity if feasible in your layout.
I have a ListView with a GridView in my C# WPF application. The ItemsSource is bound to a ListCollectionView created on the ViewModel from an ObservableCollection<MyClass>. I use the ListCollectionView for dynamic sorting, filtering and grouping, all of which can be adjusted or turned on/off from the View.
When I alter the filter or turn the grouping on/off, all of the visual list view items are recreated, which causes the UI to freeze for about a second. Since I have about 250 items displayed and there are about 10 columns (some of which have cell templates with a progressbar), this comes as no surprise.
Now, I know that the obvious answer is to enable virtualization. This however, brings some undesirable effects, such as scrolling becoming jerky or the scroll-bar changing its size as you scroll (this happens with grouping on, since the groups vary in height and so the virtualizing stack panel can not calculate the total height properly at first).
What I would like to do is to have the ListView keep a visual element for every item in the raw list (un-filtered and un-sorted, i.e. the ObservableCollection<MyClass>) and then only add to or remove from the visual tree depending on the changes in the ListCollectionView.
I hope this solution should boost my app's performance, since I rarely change the raw list, but I often alter filtering, sorting and grouping.
Do I need to create a custom control inheriting from ListView (or GridView) to do this, or is there another way?
Try to use DeferRefresh, this delay automatic refresh until the defer cycle is existed. See if that helps.
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(SomeListView.ItemsSource);
using (view.DeferRefresh())
{
view.GroupDescriptions.Clear();
view.GroupDescriptions.Add(new PropertyGroupDescription("Country"));
view.GroupDescriptions.Add(new PropertyGroupDescription("Active"));
}
http://blogs.msdn.com/b/matt/archive/2008/08/28/collectionview-deferrefresh-my-new-best-friend.aspx
To be clear I'm talking about Grid - not GridView or DataGrid or anything like that.
All I found online was about GridView and such.
I want to be able to select items with a mouse click or drag from a Grid.
What I have is a table filled with text implemented through a Grid. I want to be able to select "cells" in the Grid.
The reason I don't use DataGrid is because I couldn't find a way to set a cell's span.
Thank you,
Dolev.
I had nearly the same approach some month ago: Dynamic ui with rows and columns
Maybe this will help you.
In the end I used Selector.IsSelected attached property.
Selector Class
I modified the MouseDown, MouseUp, MouseMove event to record a rectangle created when dragging the mouse while the left button is held. Then I checked which cells are within that rectangle.
As a double check to see that the cell is really selected I used Selector.SetIsSelected and Selector.GetIsSelected.
I have a scroll view that holds about 614 Grid Controls (it's used as a book index, with each grid points to certain place at the book), inside each grid about 4 textblocks showing information about that choice....
The content is static inside all the textblocks. The thing is, when loading all that content , the phone becomes quiet unresponsive for a while... it takes time to load that page and navigate to it from another pages.
I want another solution for all that items to be shown correctly and also each grid view of the 600 has it's own clicked event handler to be able to point it to the page in the book.
I read about some hard ways to do that, I was thinking maybe I can only load the index as a very "tall" image with the index written inside it and then detect where the user tapped and calculate the index page from that ? is that efficient? or maybe there's something else ?
What is happening is the scroll view is iterating through all 600 items to measure the height of each entry so that it knows how big to render the scrollbars.
It is better to use a ListBox in this case before WP7 will only render the visible items only. Even then, I've heard of performance issues when you hit 2000 rows.
If you are interested in how virtualization works, Samuel Jack has written one that scales well (albeit not for WP7), but he has detailed writeups on the decisions he made.
https://github.com/samueldjack/VirtualCollection/tree/master/VirtualCollection/VirtualCollection
See his write ups on:
Data Virtualization and Stealth Paging
Silverlights Virtual Collection
A Virtualizing Wrap Panel
Assume two observable collections A and B. Bind your collection A to your UI. Every time fill you collection B. Everytime whne UI is refreshed clear A. Once the UI is loaded, via an event trigger start filling of items from B -> A, as it is an Observable Collection and if you are using INotifyPropertyChanged correctly the items will start appearing on the UI one by one. (Lazy Loading). You may alter this approach according your implementation. I myself am following this approach. Hope it helps for you too.
I have a Grid control with 6 rows and 6 columns.
On the top row, I have a dropdown that can have two states. (New or Used)
When I'm in the New state, I have two controls. Yellow Control in Row 3, Col 1 and Red Control in Row 5, Col 1
When I'm in the Used State, I want to swap the locations of the controls so that Red Control occupies Row 3, Col 1 and Yellow control occupies Row 5, Col 1.
Is this possible in Silverlight?
What you really want is the WPF triggers. Unfortunately, triggers are not supported in Silverlight, so that's not an option for you.
You could try the VisualStateManager class. Granted, its main purpose it to maintain transitions between visual states of the control, and thus it uses story boards and does anymation of the properties; hence, it might not work with the Grid.Column property.
Tim Heuer has a short introduction of VSM. Here's an opinion on the shortcomings of VSM.
You can also build you custom state manager on top of the VSM, which can give you state management without animated transitions and also potential support for properties not supported by the VSM class.
Or you could just have your own method that you call when the state is changed (you should know when that happens) and explicitly change the Grid.Column property on the two controls. The main drawback is that your code now has explicit knowledge about the visual representation and the layout and how it is tied to the state.
For that you can use the SetValue method.
You can do that on the event handler of the dropdown as follow:
_rowPanel1 = 2;
_rowPanel2 = 1;
panel1.SetValue(Grid.RowProperty, _rowPanel1);
panel2.SetValue(Grid.RowProperty, _rowPanel2);
Going further you could bind the Grid.RowProperty (and/or column) on the panel to
a clr property of a class that implements INotifyPropertyChanged.
Actually, the Grid class contains methods like:
Grid.SetRow(controlName, row_position);
Grid.SetColumn(controlName, col_position);
Grid.SetColumnSpan(controName, integer);
that I was able to use to swap my controls.
This works OK, because I only have one Grid in my control, however, I don't think that this would work if my control had multiple grids.
Add a Grid to the cells that need dynamic content. Add a method to handle dropdown selected item changed event. When it changes, dynamically clear then set the contents of the grids in their respective cells like so:
myContainerGrid.Children.Clear();
myContainerGrid.Children.Add(myNewControl);
If the content is more complex, you can wrap each up into a separate user control and dynamically load it into the container grid.
--Matt