Hi,
I am trying to write a Prism (CAL) adapter for the XamTilesControl, and in my implementation I would like to have only one active tile, and this tile should be the one and only maximized tile. So, maximizing a tile should make it's view active (easily handled by hooking into the TileStateChanged event), and when the view is made active programmatically then the tile should be maximized, and that's where I run into problems.
When a new view is added to the prism region, I add it to the tile control, then I attempt to get the tile by calling TileFromItem(), but this returns null. :( After reading some other posts I tried calling UpdateLayout() first, but that didn't help, but after a little more reading I found another suggestion to use Dispatcher.BeginInvoke(). In the end I had to use the following code (_instance is my XamTilesControl):
_instance.Dispatcher.BeginInvoke((Action)(() => { _instance.UpdateLayout(); Tile tile = _instance.TileFromItem(e.NewItems[0]); if (tile != null) { tile.State = TileState.Maximized; } }));
This did allow me to access the Tile for the view, and to set it's state to Maximized, but unfortunately it doesn't actually maximize the view! Instead the view appears to be still in normal mode, but it does have a minimize button (as opposed to a maximize button when I don't set the tile state to Maximized), which implies that the tile thinks it's maximized! If I click the button it changes to a Maximize button and the tile remains the same, when I click it again it maximizes.
So I have two problems, first I would like to know the proper way to obtain the Tile after adding an item to the Items collection, and second I would like know how to maximize the tile programmatically. If anyone has any ideas I would be very grateful.
Thanks.
Brian
Hi Brian,
I am aware of an issue that was resolved in earlier service releases concerning a newly added tile not being visible without using threading. It was an older issue prior to the release of 2011.1. Please let me know what product and service release you are using.
Secondly you mentioned that you want to only have one maximized tile at a time. The xamTilesControl MaximizedModeSettings has a property, MinimizedTilesExpansionMode, which you can set to AllowOne to allow only one maximized tile at a time.
It appears that you are using the appropriate method to acquire the tile that you want to maximize by using Tile tile = tilesControl.TileFromItem(item). And setting the tile’s State to TileState.Maximized should cause that tile to be maximized and, in conjunction with the previous setting I mentioned, cause it to be the only maximized tile.
I’m a little confused if your code is in the TileStateChanged event or some other event. The TileStateChanged event should provide you with the affected tile directly from the arguments.
It might be helpful if you could provide me with a small sample.
Hi Marianne,
I am using the latest version of the Infragistics libraries, with the latest service release: 11.1.20111.2113.
I am writing an adapter for the XamTilesControl to be used with the Prism framework, and the code to add the tile is being executed inside an event handler that is called when a new view is added to the Prism region. If you're not familiar with Prism, I think this event is probably being raised from within the "OnChanged" handler for an attached property, which is being set in the XAML for the view that I am trying to add to the tiles control. Hope that makes sense. :/
If you create a simple WPF application and add a tile control to the main window, then add the code below in the code behind file, it will partially replicate the problem:
private void Window_Loaded(object sender, RoutedEventArgs e) { String testItem = "Item1"; xamTilesControl1.Items.Add(testItem); Tile tile = xamTilesControl1.TileFromItem(testItem); if (tile != null) { // This is never reached! tile.State = TileState.Maximized; } else { // delay the maximizing of the tile until after tile is created xamTilesControl1.Dispatcher.BeginInvoke((Action)(() => { xamTilesControl1.UpdateLayout(); Tile lazyTile = xamTilesControl1.TileFromItem(testItem); // if we have a tile now if (lazyTile != null ) { lazyTile.State = TileState.Maximized; } }) //, DispatcherPriority.ContextIdle ); } }
The tile is always null when first added here, so the dispatcher is used to delay setting the state to Maximized. This works for this simple scenario, but in my actual scenario it doesn't (I can get the tile, but setting the Maximized state does not actually cause the window to get maximized), however adding the DispatcherPriority.ContextIdle parameter (commented out in the code above) seems to fix my problem! :)
It looks like some kind of timing issue to me, so my concern is that my workaround may not be reliable, and it would be much better if I could obtain the tile as soon as I add the new view, and then set it's state to Maximized immediatly and have this actually maximize the tile when it's displayed. :)
The first thing I noticed is that you are defining a string, instead of a tile object. I used your code and changed the string to a tile, setting the Header and Content and then added to the items collection. I was immediately able to retrieve the object and set the maximized state.
//Declare tile, add and then retrieve
Tile tile1 = new Tile
{
Header = "Tile 1",
Content = "Content Area"
};
this.xamTilesControl1.Items.Add(tile1);
Tile tileGet = xamTilesControl1.TileFromItem(tile1);
if (tileGet != null)
// This is never reached!
tileGet.State = TileState.Maximized;
}
else
// delay the maximizing of the tile until after tile is created
xamTilesControl1.Dispatcher.BeginInvoke((Action)(() =>
xamTilesControl1.UpdateLayout();
Tile lazyTile = xamTilesControl1.TileFromItem(tileGet);
// if we have a tile now
if (lazyTile != null)
lazyTile.State = TileState.Maximized;
})
//, DispatcherPriority.ContextIdle
);
Let me know if this resolves your issue.
Yes, in my actual code I add UserControls as the tile control Items (I just used a string in the demo for simplicity), and this makes the code easier for the adapter when it comes to adding and removing views as it can find the view in the Items collection directly.
If I create Tile items and add these instead, then I have to iterate over the items collection and check for a matching Content to find a particular view, this is slightly more messy, and since the tiles contol supports adding the UserControls directly I used this approach. But as I've found out, the tile gets created lazily when you do this, and this has caused a lot of problems for me, so I recoded to wrap my views in Tile objects before adding them, as you suggested, and this does work correcty, just needs a little more code in the rest of the adapter to cope with the level of indirection this adds. :/
Thanks for your help.
.
Thank you for the update. Please let me know if I can be of further assistance.
I just noticed that the headers of my tiles are no longer displaying the header text. Previously I had set the HeaderPath property of teh XamTilesControl to specify which property on my user control to bind to for this text, but this does not appear to work when you add Tile items directly. :(
I have had to modify my adapter class to set each Tile's Header explicitly, and to do that meant I had to use a cast to convert it's contained user control's DataContext to my view model type, which makes it more tightly coupled than I would like. :(
Is there a way to have the Tile bind it's Header to a property of it's Content object, possibly by specifying a HeaderPath as the XamTilesControl does?
Thanks,
The HeaderPathProperty is the xamTilesControls’ dependency property for setting the path to a value in the source that will be used to initialize the Header of each Tile and you can bind to it. I’m guessing that you set the HeaderPath in code.
The tiles also have a HeaderProperty which is a dependency property. You can also set each tile's header as I did in my snippet when I add a single tile.
I think the question is how are you setting / binding to this property? Or are you binding to this property? You should be able to set the HeaderPath or Header of each tile.
Glad I could help and thanks for posting your solution code here for the next person.
Please let me know if you have any further questions.
Thanks for the info, I hadn't realized that I could just bind to the Header property! :) I have solved my problem with the code below:
// NB: This would be a reference to the actual user controlUserControl myControl = new UserControl();
// configure binding for headerBinding bind = new Binding("DisplayName");bind.Source = myControl.DataContext;bind.Mode = BindingMode.OneWay;
// add control to a new tileTile tile = new Tile() { Content = myControl };
// set binding for Headertile.SetBinding(Tile.HeaderProperty, bind);
// add tile to tiles controltilesControl.Items.Add(tile);