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 к коллекции экранов (виджетов)

Дайте мне знать, если вам нужен более подробный пример.

Другие вопросы по тегам