Добавьте несколько представлений внутри представления с помощью WPF и Caliburn.Микро
Я пытаюсь научиться использовать Caliburn.Микро с 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
Edit: я все еще не могу заставить его работать, проблема, похоже, в загрузчике или что-то еще. Но чтобы уточнить, вот мой код, который я запускаю для testproject.
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-изменения в приложение.язык XAML)
public class BootStrapper : Bootstrapper<MainViewModel>
{
}
пожалуйста, помогите мне здесь! Кажется, это некоторые основные вещи, которые мне не хватает:)
3 ответов
EDIT-новый (более полный) ответ ниже:
хорошо, C. M делает много вещей для вас, все дело в том, чтобы ваши классы и xaml были подготовлены для C. M, чтобы найти его. Как сказано выше, я предпочитаю писать явный код, а не полагаться на неявные предположения кода фреймворком.
Итак, загрузчик, из проекта 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 была контейнером, и только контейнером, логика событий обрабатывается в другом месте. Но вы могли бы так же легко иметь свою логику ручки здесь - но это некоторое время другое обсуждение.
теперь каждая модель представления ребенка также нужно экспортировать себя, чтобы 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
требует YourFirstViewModel
и YourSecondViewModel
(и другие ViewModels) требуются в его конструкторе, поэтому C. M создает каждый из них. Все эти ViewModels заканчиваются в МОК (что делает вашу жизнь намного проще позже - опять же, целая другая дискуссия).
C. M обрабатывает назначение datacontext от вашего имени каждому из представлений, потому что вы указываете, к какой виртуальной машине привязываться с помощью строки, такой как cal:Bind.Model="Your.Namespace.ViewModels.YourFirstViewModel"
если повезет, это должно получить вас начатый. Также обратитесь к примеру проекта C. M Caliburn.Micro.HelloEventAggregator
поскольку он делает именно то ,что вы ищете (хотя, это описано как демонстрация агрегатора событий, что также очень полезно - но опять же, другое обсуждение)
(оригинальный ответ для почтения, ниже)
вам нужно сделать это:
<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.м не может найти ее.
[Export(typeof(YourViewModel))]
public class YourViewModel : IShell
{
...
}
затем вы можете вложить свои пользовательские элементы управления, как вы считаете нужным. Это очень хороший способ использовать C. M, и вы найдете его очень масштабируемым. Единственный слабость заключается в том, что View и ViewModel должны быть в одном проекте (насколько я могу судить). Но сила этого подхода заключается в том, что вы можете разделить классы View и View Model на разные пространства имен (в одном проекте), если хотите, чтобы все было организовано.
в качестве комментария к c.m я предпочитаю этот метод, на самом деле, даже если мне не нужно nest View UserControls и тому подобное. Я бы предпочел явно объявить witch VM, что представление обязательно (и все же пусть C. M обрабатывает всю тяжелую работу в IoC), чем пусть c.m "выяснить это" из подразумеваемого кода.
даже с хорошей структурой: явный код более ремонтопригоден, чем подразумеваемый код. Указание модели связанного представления позволяет четко указать, каким должен быть контекст данных, поэтому вам не нужно будет угадывать позже.
лучший подход-использовать 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(...); }
}
в приложении file.код 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 }