I have a GridView as my zoomed out view in a SemanticZoom control. This GridView uses a custom DataTemplateSelector as the ItemTemplateSelector. It shows an item for each content group that my app shows.
The template is different depending on whether the group is empty or not. This works fine on load, but it doesn't update when a group becomes empty or stops being empty.
I've found that the ItemTemplateSelector is only run when the page is first shown. How can I force the DataTemplateSelector get run again.
The WPF questions on this topic all suggest triggers, but these aren't available in WinRT XAML.
I've found an answer to a similar WPF question that answers this in a way that works in WinRT:
https://stackoverflow.com/a/11327087/31569
Basically you set the ItemTemplateSelector to null and then set it again. Like this:
var templateSelector = MyGroupView.ItemTemplateSelector;
MyGroupView.ItemTemplateSelector = null;
MyGroupView.ItemTemplateSelector = templateSelector;
This works, but happy to be told if there is a better way to do this.
I find it easier to just just remove the item in need updating from the collection and adding it back. This forces the GridView or ListView to apply the template. This is easy to do in MVVM world.
var itemToReload; //The object who's template needs updating
var reloadIndex = this.SomeCollection.IndexOf(itemToReload);
this.SomeCollection.Remove(itemToReload);
this.SomeCollection.Insert(reloadIndex, itemToReload);
One thing to note, is that if the item is a "Selected" item, you'll need to reapply that selection.
Related
So I'm trying to wrap my head around MVVM and I'm finding that I have more questions than answers. The tutorials don't go far enough for me when it comes to the next step...
Basically I want a list of items and then a way to get the detail of each item.
Below is the examples that I've found online and they work great for displaying the list, but I need to know how I can use my VM to get the detail of this item.
private IList<item> m_items;
private IList<item> m_Item;
private IList<item> getItemDetail(Int32 iId)
{
var myItem =
from i in items
where i.iId == iId
select i;
m_Item = new List<item>();
foreach (var item in myItem)
{
m_Item.Add(item);
}
return m_Item;
}
public myViewModel()
{
m_items = new List<item>
{
new item(1, "test,),
new item(2, "test2"),
new item(3, "test1")
};
m_Item = new List<item>();
m_Item = getItemDetail(iId);
}
Update:
I updated my View Model code above. I think what I've done is I have added another List where when the user navigates to a detail page the view model gets called with the specific ID which then populates the detail List. I probably don't need a list here but I wanted to try to keep it consistent with the main page code.
In my detail page I'm setting up the VM this way:
itemViewModel VM = new itemViewModel((Int32)navigationParameter);
DataContext = VM;
When I break on the VM variable I see my 2 lists. However, my binding doesn't work on the XAML. If I need to post some sample XAML let me know. I can do that but I'm hoping there is something I'm missing here.
I'm trying to learn MVVM and I want to do things right. So instead of continuing down a wrong path I would really like to know the "right" way of doing things. So if you see errors, please let me know.
Thanks!
right, i'd suggest you go back to basics first and watch Laurent's Mix sessions about MVVM, you find links to then from the mvvmlight site on codeplex.
but to break it down you've hit a few of the hurdles I did when I first started.
1: (the biggest gotcha) for databinding to work, you must expose data using a property (get and set pattern), just a list variable won't work. this goes for everything you want to bind to. The alternative is to set item sources directly in code but you will loose all the features of databinding, including updates.
2: to understand databinding you need to understand the INotifyProperty changed pattern, this is the underlying gubbins (technical term ;-D) to enable binding to work properly. as suggested start a new "master/details" project template and walk through it, from the viewmodels holding the data to the views (pages) looking at the data in the view model
3: use observablecollections for lists, they are just better for binding and are basically just lists with extras
4: remember you can also bind the "selecteditem" or "selectedindex" of a listbox to capture what the user has selected, just be sure to set the binding to "twoway" so the view can push data to the viewmodel and not just read, like this: {binding myselecteditem, mode="twoway"}
hope this helps but if your still stuck Laurents videos are the best, just watch them a few times and follow what he does line by line
I believe you want to use what Microsoft calls the "master-detail binding scenario", where several controls bind to a single collection or to its selected item. To do so, you need to bind to a so called collection view, which is just a layer on top of the collection used by WPF. For instance, you can bind a ListBox's ItemSource and a ContentControl's Content to the same collection view, and the ContentControl will display the details of the the ListBox's selected item.
see: http://msdn.microsoft.com/en-us/library/ms752347.aspx#master_detail_scenario
P.S. you may want to use an ObservableCollection instead of a List, and make sure your view model implements INotifyPropertyChanged.
When i define a control in DataTemplate, how to get reference of this control ?
If the control in ControlTemplate of Style , how to get ?
You should instead tell us why you would need to reference a control inside a template.
Consider that the control will be rendered multiple times, so getting a single reference does simply not make any sense.
The most common approach to this is to 'name' the element that you wish to locate via x:Name="MyElementName", you can then use the FindName method to locate the names element. If your DataTemplate is being used in an ItemsControl to render multiple copies of yoru XAML markup, then clearly there will be a number of elements that share this same name. For this reason, there is a concept known as XAML namescope, you should read up on this to understand the scope of the name you provide.
If you require a more generic method for searching for elements in the visual tree, try Linq-to-VisualTree, you can use it to query you UI, for example:
var itemsFluent = this.Descendants<TextBox>()
.Where(i => i.Ancestors().FirstOrDefault() is Grid);
The above query will find all TextBoxs that have a Grid as a direct parent.
Finally, if you can avoid doing any of this, by using databinding, or event bubbling then do so! it is much easier.
I have a container element in which I create on the fly/place() a form, then another one..etc.
My goal is to switch between them i.e. hide all and show only the active form.
It hides alright, but I can't show the active back.
I tried using:
.style.display(none<->block) and visibility(visibility<->hidden)
dojo.style(...)
resize() and startup() after the changes
Several other variants i found on Internet from old dojo's
Nothing works.
/I need it to work with display, so that it does not occupy space./
Can you tell me what is the correct way to show and hide with dojo()
Also looked at this one :
How do I dynamically show and hide an entire TabContainer using DOJO?
Does not work.
The pseudo code I use is something like this :
....
//find or create the FORM element
form = dijit.byId(...);
if(typeof form != 'object') {
form = dojo.create('form', ....);
dojo.place(form,'containerx','last');
}
//hide all
dojo.query('#containerx > *').forEach(function(item){
dojo.style(item, 'visibility','hidden');// and all other variants i mentioned
})
//show only the current form
dojo.style(form, 'visibility','visible');
//if the dojo form obj was already created, then skip it
if (this.form_obj) return;
....build the form and the elements....
this.form_obj.startup()
thanx
I just answered the question in that thread you referenced in your question a few minutes ago. Basically it involved getting jQuery involved. Works great for me. I have all the tabs created statically (as opposed to programatically) and I'm able to manipulate whether they are shown or hidden with the help on jQuery. All the code any everything is in my post here:
How do I dynamically show and hide an entire TabContainer using DOJO?
Sounds like you might be looking for StackContainer functionality.
Just set things up so that the StackContainer has the dijit.form.Forms as children and you can use the selectChild method to choose what form to display.
Is it possible to generate dynamic WP7 controls in code behind (.cs) using .xaml template (like inflating in Android) ,
or should I generate it all manually? For example I need dynamic tabs (PivotItems)
Pete Brown recently demonstrated how to dynamically generate xaml here if you'd like to look into that route.
Dynamically Generating Controls in WPF and Silverlight
You can definitely do this:
var newItem = new PivotItem { Header = "Added" };
MyPivot.Items.Add(newItem);
Beware of potential performance implications of having lots of times though.
It is possible to do so - but definitely not recommended.
I am not sure why you would want to have more than three pivot items in any application anyway. Simply have three and reuse them as they wrap around. You only need to change the data in the pivotItems on a page transition, not create more and more of them.
I am using a Widget that contains a DataGrid object. The Widget works fine when included in the first tab (this is the visible tab), but not when I use the same code on a second tab.
The code is the same I have done several checks to make sure there are no other problems - and non Grid code is rendering fine - only the grid that has a problem. I have tried setting the height and width manually and this just results in a large grey rectangle on the second tab.
Do I need to tell the Grid to refresh in some way - or is it a property for the TabContainer?
Help - this is driving me mad!
Yeah, that's a big problem with the grid. If you use it declaritively in a tab container, it won't render properly on the non-visible tabs. It needs to calculate height/width (even though you specify them)...as you have seen.
The way I got around it was to create the grids programatically on tab select. I posted about my solution on the dojo forums. My code sample is over on github. It's a bit too large to post here methinks. Let me know if you want it, and i'll edit my answer.
There's also a discussion on nabble with a different solution.
"resize" works like a charm! Been looking for this for a long time (didn't know what I had to search for), thanks.
I use this routine to dynamically determine if the tab has more than one datagrid, as I may not know the ID of one single grid, maybe someone else might use that, too:
dojo.query('div#container div[id^="gridNode_"]').forEach(function(node, index, arr) {
dijit.byId(node.id).resize();
});
This will check the div with id="container" (skip that part if you want to search the whole DOM) for divs with an id starting with "gridNode_" and apply "resize" to those widgets.
An alternate approach is to resize the grid upon tab element selection. Sample code
dojo.connect(dijit.byId('my_tab_container'), "selectChild", function(child){
// if second tab (could be any...) selected
if(child.id == 'mySecondTabId'){
var myGrid = dijit.byId('myGridInsideTabId');
if(myGrid != null) myGrid.resize();
}
});