Подтвердить что ты не робот

Добавить несколько представлений внутри представления с помощью WPF и Caliburn.Micro

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

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

Другое представление, с viewmodel: MyControlViewModel

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

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

Я пробовал с разными загрузчиками и использовал что-то вроде 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-reference:

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

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

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

public class BootStrapper : Bootstrapper<MainViewModel>
{
}

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

4b9b3361

Ответ 1

EDIT - новый (более полный) Ответ Ниже:

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

Итак, Bootstrapper, из стандартного проекта C.M, просто отлично.

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 требует наличия других ViewModels. В моем конкретном случае мне нравится, что мой MainViewModel является контейнером и контейнером, логика событий обрабатывается в другом месте. Но вы можете так же легко иметь логику Handle здесь, но это еще одно обсуждение.

Теперь каждая модель View View также должна экспортировать себя, поэтому C.M знает, где их найти.

[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 или один из дочерних представлений

<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>

Что, черт возьми, происходит здесь?

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

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

Если вам повезет, вам нужно начать. Также см. Пример проекта C.M 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", которая указывает точную модель просмотра для привязки этого представления к.

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

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

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

В качестве комментария к c.m Я предпочитаю этот метод, даже если мне не нужно вставлять View UserControls и тому подобное. Я предпочел бы явно объявить виртуальную виртуализацию, с которой связан вид (и все еще позволяет C.M обрабатывать весь тяжелый подъем в IoC), чем позволить c.m "выяснить это" из подразумеваемого кода.

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

Ответ 2

Лучшим подходом является использование 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(...); }
}

Ответ 3

в файле 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
}