Добавить несколько представлений внутри представления, используя WPF и Caliburn.Micro - PullRequest
13 голосов
/ 24 октября 2011

Я пытаюсь научиться использовать Caliburn.Micro с WPF.Как я могу добавить несколько представлений внутри представления?

<Window x:Class="ProjectName.Views.MainView"
         ...>
<Grid>
        <views:MyControlView  />
</Grid>
</Window>

Другое представление с моделью представления: MyControlViewModel

<UserControl x:Class="ProjectName.Views.MyControlView"
         ...>
<Grid>
    ...
</Grid>
</UserControl>

Если я просто добавлю представление, оно не обнаружит, что оно имеетмодель представления с соответствующим названием.Как я могу связать это с этим?

Я пробовал с различными загрузчиками и используя что-то вроде cal: Bind.Model = "путь / имя класса / слияние двух".Попытался добавить это в mainview и в usercontrol (MyControlView).Я ОЧЕНЬ благодарен за любую помощь в этом вопросе.Я в значительной степени застрял, и я действительно хочу использовать Caliburn.Micro:)

С наилучшими пожеланиями, diamondfish

Редактировать: Я все еще не могу заставить его работать, проблема, кажется,быть в начальной загрузке или что-то еще.Но только для пояснения, вот мой код, который я запускаю для тестового проекта.

MainView xaml:

<Window x:Class="Test.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
    xmlns:views="clr-namespace:Test.Views"
    Title="MainWindow" Height="360" Width="640">
<Grid>
    <views:MyControlView />
</Grid>

Код MainViewModel:

public partial class MainViewModel : PropertyChangedBase
{
}

MyControlView xaml:

<UserControl x:Class="Test.Views.MyControlView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
         cal:Bind.Model="Test.MyControlViewModel"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <TextBlock Text="{Binding MyProp}"/>
</Grid>

Код MyControlView:

public class MyControlViewModel : PropertyChangedBase
{
    public string MyProp
    {
        get { return "Working"; }
    }
}

Снимок экрана с ошибкой: http://clip2net.com/s/1gtgt

Я пытался

cal:Bind.Model="Test.ViewModels.MyControlViewModel" 

.Также попробовал ссылку cal:

xmlns:cal="http://www.caliburnproject.org"

Снимок экрана моего проекта http://clip2net.com/s/1gthM

Поскольку документация в основном предназначена для Silverlight, а иногда для Caliburn, а не CM, я мог бы реализоватьзагрузчик ошибся.Для этого тестового проекта это так: (с .xaml-change в App.xaml)

public class BootStrapper : Bootstrapper<MainViewModel>
{
}

Пожалуйста, помогите мне здесь!Кажется, мне не хватает некоторых базовых вещей:)

Ответы [ 3 ]

17 голосов
/ 24 октября 2011

Лучше всего использовать ContentControl на главном экране и присвоить ему то же имя, что и у общего свойства на MainViewModel, которое имеет тип MyControlViewModel. Э.Г.

MainView.xaml

<ContentControl x:Name="MyControlViewModel" />

MainViewModel.cs

// Constructor
public MainViewModel()
{
  // It would be better to use dependency injection here
  this.MyControlViewModel = new MyControlViewModel();     
}

public MyControlViewModel MyControlViewModel
{
  get { return this.myControlViewModel; }
  set { this.myControlViewModel = value; this.NotifyOfPropertyChanged(...); }
}
16 голосов
/ 24 октября 2011

РЕДАКТИРОВАТЬ - Новый (более полный) ответ ниже:

Хорошо, CM делает много вещей для вас, это все о том, как подготовить ваши классы и xaml к CM, чтобы иметь возможность найти его.Как уже было сказано выше, я предпочитаю писать код явно, а не полагаться на предположения о неявном коде, создаваемые платформой.

Итак, Bootstrapper из проекта CM по умолчанию просто в порядке.

public class AppBootstrapper : Bootstrapper<MainViewModel>
{
    // ... You shouldn't need to change much, if anything
}

Раздел `Bootstrapper 'очень важен, он указывает, какой ViewModel является вашим первым или основным экраном при запуске приложения.

[Export(Typeof(MainViewModel))]
public class MainViewModel : Screen,  IShell
{
    [ImportingConstructor]
    public MainViewModel(YourFirstViewModel firstViewModel, YourSecondViewModel secondviewModel) // etc, for each child ViewModel
    {
    }
}

В [ImportingConstructor] вам не нужноделать что-либо кроме указания, что MainViewModel требует присутствия других ViewModel.В моем конкретном случае мне нравится, что мой MainViewModel является контейнером, и только контейнером, логика событий обрабатывается в другом месте.Но вы могли бы также легко использовать здесь свою логику Handle - но это совсем другое обсуждение.

Теперь каждая дочерняя View View также должна экспортировать себя, чтобы CM знал, где их найти.

[Export(Typeof(YourFirstViewModel))]
public class YourFirstViewModel : IShell
{
    // VM properties and events here
}

Нет необходимости указывать конструктор импорта, если вы просто используете конструктор по умолчанию.

Теперь каждый из ваших представлений для них будет выглядеть примерно так:

<UserControl x:Class="Your.Namespace.MainView"
             xmlns:views="clr-namespace:Your.Namespace.Views"
             xmlns:cal="http://www.caliburnproject.org"
             cal:Bind.Model="Your.Namespace.ViewModels.MainViewModel"
             MinWidth="800" MinHeight="600">
    <StackPanel x:Name="RootVisual">
        <views:YourFirstView />
        <views:YourSecondView />
        <!-- other controls as needed -->
    </StackPanel>
</UserControl>

XAMl или один изthe child-views

<UserControl x:Class="Your.Namespace.Views.YourFirstView"
             xmlns:cal="http://www.caliburnproject.org"
             cal:Bind.Model="Your.Namespace.ViewModels.YourFirstViewModel"
             MinWidth="800" MinHeight="600">
    <Grid x:Name="RootVisual">
        <!-- A bunch of controls here -->
    </Grid>
</UserControl>

Какого черта здесь происходит на самом деле?

Хорошо, CM видит в загрузчике, что MainViewModel является отправной точкой из-за строки, указывающей public class AppBootstrapper : Bootstrapper<MainViewModel>,MainViewModel требует, чтобы YourFirstViewModel и YourSecondViewModel (и другие ViewModels) требовались в его конструкторе, поэтому CM конструирует каждый из них.Все эти ViewModel попадают в IoC (что значительно облегчает вашу жизнь позже - опять же, совершенно другое обсуждение).

CM обрабатывает присвоение текста данных от вашего имени каждому представлению, потому что вы указываете, какойВМ связывается с линией вроде cal:Bind.Model="Your.Namespace.ViewModels.YourFirstViewModel"

Если повезет, это поможет вам начать.Также обратитесь к примеру проекта CM Caliburn.Micro.HelloEventAggregator, поскольку он делает именно то, что вы ищете (хотя он описан как демонстрация Event Aggregator, что также очень полезно - но опять же, другое обсуждение)

(ОригиналОтвет на почтение, ниже)

Вам необходимо сделать следующее:

<UserControl x:Class="Your.Namespace.Here.YourView"
             xmlns:cal="http://www.caliburnproject.org"
             cal:Bind.Model="Your.Namespace.Here.YourViewModel"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="1024">
  <YourControlLayout />
</UserControl>

Обратите внимание на строку cal:Bind.Model="Your.Namespace.Here.YourViewModel", которая указывает точную модель вида, к которой привязывается этот вид.

Не забудьте экспортировать тип вашего класса, или cm не может его найти.

[Export(typeof(YourViewModel))]
public class YourViewModel : IShell
{
    ...
}

Тогда вы можете вкладывать свои пользовательские элементы управления по своему усмотрению.Это очень хороший способ использовать CM, и вы найдете его очень масштабируемым.Единственным недостатком является то, что View и ViewModel должны быть в одном проекте (насколько я могу судить).Но сила этого подхода в том, что вы можете разделить классы View и View Model на разные пространства имен (в рамках одного проекта), если хотите, чтобы все было организовано.

В качестве комментария к cm я предпочитаю этот метод,на самом деле, даже если мне не нужно вкладывать View UserControls и тому подобное.Я предпочел бы явно объявить, что с VM связан View (и все же позволить CM обрабатывать всю тяжелую работу в IoC), чем позволить cm «выяснить это» из подразумеваемого кода.

Даже с хорошей структурой: явныйкод более понятен, чем подразумеваемый код.Преимущество указания связанной модели представления состоит в том, что она четко указывает, каким должен быть ваш контекст данных, поэтому вам не нужно будет угадывать позже.

1 голос
/ 04 апреля 2013

в файле App.xaml.cs, в метод GetInstance добавьте следующие строки

protected override object GetInstance(Type service, string key)
{
    if (service == null && !string.IsNullOrWhiteSpace(key))
    {
        service = Type.GetType(key);
        key = null;
    }
    // the rest of method
}
...