MVVM, ViewModelLocator, динамически отображать View с ViewModel на основе свойства
У меня есть вопрос дизайна. Пожалуйста, посмотрите на прикрепленное изображение, чтобы получить представление о дизайне приложения. По сути, мне просто нужна помощь в поиске правильного подхода.
У меня есть View и ViewModel, которая содержит TileUserControl. Он берет коллекцию плиток и отображает их в определенном размере, цвете, порядке и так далее. Он также способен группировать сказки по группам и позволяет пользователю добавлять и удалять плитки.
Объект Tile выглядит следующим образом.
public class Tile
{
public int ID { get; set; }
public string View { get; set; }
public List<string> Views { get; set; }
public string TileSize { get; set; }
}
Пока все хорошо. Все отлично работает
Все плитки имеют контент. Я хочу установить содержимое для View и ViewModel, соответствующих строке View на объекте Tile.
Я использую MVVM Light, но могу также использовать Caliburn Mico. Элемент управления плитками - это DevExpress TileLayoutControl для WPF.
DevExpress TileLayoutControl doc
РЕДАКТИРОВАТЬ: обновлено с 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>
Моя проблема заключается в том, как загрузить UserControl из Tile.View в содержимое Tile. Я триде выше с DataTrigger и DataTemplate.
StringToTileConverter просто возвращает имя ViewModel.
В настоящее время я использую Caliburn Micro, и моя привязка отлично работает вне шаблонной части, но я не могу заставить их работать с DataTemplate.
Кроме того, весь этот код не очень чистый, поэтому я спрашиваю, есть ли у кого-нибудь более чистый способ сделать это.
1 ответ
Поскольку вы используете Caliburn.Micro, вы можете воспользоваться его встроенным ViewLocator. Вам не нужны конвертеры или DataTriggers, так как вы можете определить DataTemplate следующим образом:
<DataTemplate>
<ContentControl Width="100" Height="100" cal:View.Model="{Binding}" />
</DataTemplate>
Вы можете найти это полезным: привязка ListBox к коллекции экранов (виджетов)
Дайте мне знать, если вам нужен более подробный пример.