Caliburn.Micro, чтобы связать UserControls в MainView с их ViewModels
У меня есть MainView.xaml, привязка к MainViewModel просто прекрасна.
Что я хотел попробовать, так это разделение большого количества элементов управления, которые у меня есть на моей основной форме, в UserControls.
Теперь я помещаю UserControls в папку Views вместе с MainView и назвал их LeftSideControlView.xaml и RightSideControlView.xaml. Соответствующие ViewModels находятся в папке ViewModels с именем LeftSideControlViewModel и т.д.
Я успешно добавил usercontrols в mainview:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<UserControls:LeftSideControlView cal:Bind.Model="{Binding}" />
<UserControls:RightSideControlView cal:Bind.Model="{Binding}"
Grid.Column="1" />
</Grid>
они правильно отображаются в дизайнере. Здесь один из них в xaml:
<UserControl x:Class="TwitterCaliburnWPF.Library.Views.LeftSideControlView"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel>
<Label x:Name="Text" FontSize="25" HorizontalAlignment="Center" Margin="5"/>
<TextBox x:Name="TextBox1"
Width="200"
HorizontalAlignment="Center" FontSize="25" Margin="5" />
<Button Width="200" Height="50" Content="Button!" Margin="20" />
</StackPanel>
</Grid>
Я добавил модели viewmodels и их интерфейсы внутри AppBootstrapper для Caliburn, используя Castle.Windsor.
public class ApplicationContainer : WindsorContainer
{
public ApplicationContainer()
{
// Register all dependencies here
Register(
Component.For<IWindowManager>().ImplementedBy<WindowManager>().LifeStyle.Is(LifestyleType.Singleton),
Component.For<IEventAggregator>().ImplementedBy<EventAggregator>().LifeStyle.Is(LifestyleType.Singleton),
Component.For<ILeftSideControlViewModel>().ImplementedBy<LeftSideControlViewModel>(),
Component.For<IRightSideControlViewModel>().ImplementedBy<RightSideControlViewModel>()
);
RegisterViewModels();
}
private void RegisterViewModels()
{
Register(AllTypes.FromAssembly(GetType().Assembly)
.Where(x => x.Name.EndsWith("ViewModel"))
.Configure(x => x.LifeStyle.Is(LifestyleType.Transient)));
}
Здесь класс LeftSideControlViewModel:
using Screen = Caliburn.Micro.Screen;
namespace TwitterCaliburnWPF.Library.ViewModels
{
public class LeftSideControlViewModel : Screen, ILeftSideControlViewModel
{
private string _text = "Hello from the Left side!";
private string _textBox1 = "Enter Text Here";
public string Text
{
get { return _text; }
}
public string TextBox1
{
get { return _textBox1; }
}
}
}
Здесь MainViewModel, и я ухожу от того, что я читал в документе Caliburn.Micro, так как раньше я пробовал это, в MainViewModel не было ничего, чтобы сказать, чтобы загрузить эти два элемента управления или показать эти два элемента управления.
Тем не менее, когда приложение запущено и запущено, значения не привязаны к пользовательским элементам управления из их соответствующих режимов просмотра.
namespace TwitterCaliburnWPF.Library.ViewModels
{
public class MainViewModel : Conductor<IScreen>
{
public MainViewModel()
{
ShowLeftControl();
ShowRightControl();
}
private void ShowRightControl()
{
ActivateItem(new RightSideControlViewModel());
}
private void ShowLeftControl()
{
ActivateItem(new LeftSideControlViewModel());
}
public string TextToDisplay
{
get { return "Coming from the ViewModel!"; }
}
}
}
Ответы
Ответ 1
Здесь вам не нужно использовать Conductor
. Это в основном используется для сценариев навигации. Просто создайте две общедоступные свойства на MainViewModel
для RightSideControlViewModel
под названием RightSide и один для LeftSideControlViewModel
, называемый LeftSide. Затем вместо создания экземпляров UserControls непосредственно в вашем MainView создайте два ContentControls
, один с x:Name="LeftSide"
, а другой с x:name="RightSide"
Это первый способ выполнения этой модели. Если вы хотите сделать это сначала, сначала сохраните определения пользовательского элемента управления в MainView, но измените Bind.Model так, чтобы он указывал на новые созданные вами свойства, например Bind.Model="{Binding LeftSide}"
В принципе, то, как у вас есть вещи, определяет... привязки просто не указывают на нужные объекты, более или менее. У вас там Дирижер, и вам этого не нужно. Вы можете захотеть сохранить его, если собираетесь надумать какую-то навигационную архитектуру. Помните, что когда вы вызываете ActivateItem на проводнике, вы в основном меняете его свойство ActiveItem; только одна модель будет активна одновременно. В приведенном выше примере вы активируете оба элемента, но только второй остается активным. Кроме того, по вашему мнению, ничто не связано с ActiveItem.
Надеюсь, это имеет смысл!