I have a design question. Please look at the attached image to get an idea of the app design. Basicaly I just need help in finding the correct approach here.
I have a View and ViewModel that holds an TileUserControl. It takes a collection of tiles, and displays them in the defined size, color, order and so one. It is also capable of grouping the tales in groups, and allowing the user to add and remove Tiles.
The Tile object look like this.
public class Tile
{
public int ID { get; set; }
public string View { get; set; }
public List<string> Views { get; set; }
public string TileSize { get; set; }
}
So far all good. Everything works fine.
All tiles have content. I want to set the content to the View and the ViewModel corresponding to the View string on the Tile Object.
I am using MVVM Light, but may also use Caliburn Mico. The tiles Control is DevExpress TileLayoutControl for WPF.
DevExpress TileLayoutControl doc
EDIT: Updated With MainTilesView XAML
<Grid>
<dxlc:TileLayoutControl Padding="60,41,0,0"
ItemsSource="{Binding Tiles}"
ScrollBars="None"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
AllowGroupHeaderEditing="False"
AllowMaximizedElementMoving="True" Background="{x:Null}">
<dxlc:TileLayoutControl.GroupHeaderStyle>
<Style TargetType="dxlc:TileGroupHeader">
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="24"/>
<Setter Property="FontFamily" Value="Segeo UI"/>
<Setter Property="FontWeight" Value="Light"/>
</Style>
</dxlc:TileLayoutControl.GroupHeaderStyle>
<dxlc:TileLayoutControl.ItemTemplate>
<DataTemplate>
<dxlc:Tile Header="{Binding Header}"
Size="{Binding TileSize}"
dxlc:TileLayoutControl.GroupHeader="{Binding GroupHeader}"
Tag="{Binding ID}"
dxlc:FlowLayoutControl.IsFlowBreak="{Binding IsNewGroup}"
Background="{Binding BackgroundColor}">
</dxlc:Tile>
</DataTemplate>
</dxlc:TileLayoutControl.ItemTemplate>
<dxlc:TileLayoutControl.Resources>
<conv:IsUserControlConverter x:Key="IsUserControlConverter"/>
<conv:StringToTileConverter x:Key="StringToTileConverter"/>
<Style TargetType="{x:Type dxlc:Tile}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=TileSize}" Value="ExtraSmall">
<Setter Property="Size" Value="ExtraSmall"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="1x1">
<Setter Property="Size" Value="ExtraSmall"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="1x1">
<Setter Property="Size" Value="Small"/>
<Setter Property="Width" Value="150"/>
<Setter Property="Height" Value="150"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="1x2">
<Setter Property="Size" Value="Large"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="2x1">
<Setter Property="Size" Value="ExtraLarge"/>
<Setter Property="Width" Value="150"/>
<Setter Property="Height" Value="310"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="2x2">
<Setter Property="Size" Value="ExtraLarge"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="2x3">
<Setter Property="Size" Value="ExtraLarge"/>
<Setter Property="Width" Value="310"/>
<Setter Property="Height" Value="470"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="3x2">
<Setter Property="Size" Value="ExtraLarge"/>
<Setter Property="Width" Value="470"/>
<Setter Property="Height" Value="310"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="3x3">
<Setter Property="Size" Value="ExtraLarge"/>
<Setter Property="Width" Value="470"/>
<Setter Property="Height" Value="470"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="4x2">
<Setter Property="Size" Value="ExtraLarge"/>
<Setter Property="Width" Value="630"/>
<Setter Property="Height" Value="310"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="4x3">
<Setter Property="Size" Value="ExtraLarge"/>
<Setter Property="Width" Value="630"/>
<Setter Property="Height" Value="470"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="4x4">
<Setter Property="Size" Value="ExtraLarge"/>
<Setter Property="Width" Value="630"/>
<Setter Property="Height" Value="630"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=TileSize}" Value="Single_1x1">
<Setter Property="Size" Value="Large"/>
<Setter Property="Width" Value="150"/>
<Setter Property="Height" Value="150"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=View,Converter={StaticResource IsUserControlConverter}}" Value="true">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ContentControl cal:View.Model="{Binding Path=View, Converter={StaticResource StringToTileConverter}, UpdateSourceTrigger=Explicit}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</dxlc:TileLayoutControl.Resources>
</dxlc:TileLayoutControl>
</Grid>
My issue is how to get the UserControl from Tile.View loaded into the Tile content. I have tride above with DataTrigger and DataTemplate.
The StringToTileConverter just Returns the name of the ViewModel.
Currently using Caliburn Micro, and my binding workes fine outside of the template part, but I can't get them to work with the DataTemplate.
Also all this code is not very clean, so therefor I ask if anyone have a more clean way to do it.
As you are using Caliburn.Micro, you can take advantage of its built-in ViewLocator. You don't need converters or DataTriggers, as you can define the DataTemplate as follows:
You may find this helpful: Binding ListBox to a collection of screens (widgets)
Let me know if you need a more throughout example.