Caliburn.Micro заставляет его привязать UserControls в MainView к их ViewModels

У меня есть MainView.xaml, просто привязка к MainViewModel.

Что я хотел попробовать, так это разделить множество элементов управления, которые есть в моей основной форме, на UserControls.

Теперь я поместил UserControls в папку Views вместе с MainView и назвал их LeftSideControlView.xaml и RightSideControlView.xaml. Соответствующие модели ViewModels находятся в папке ViewModels под названием LeftSideControlViewModel и т. Д.

Я успешно добавил элементы управления в главное окно:

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

I added the viewmodels and their interfaces inside the AppBootstrapper for Caliburn using 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, чтобы сообщить ему загрузить эти 2 элемента управления или показать эти 2 элемента управления.

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

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!"; }
      }
   }
}

person Mark W    schedule 03.04.2012    source источник


Ответы (1)


Здесь вам не нужно использовать Conductor. Это в основном используется для сценариев навигации. Просто создайте на своем MainViewModel два общедоступных свойства: одно для RightSideControlViewModel с именем RightSide и одно для LeftSideControlViewModel, которое называется LeftSide. Затем, вместо того, чтобы создавать экземпляры ваших UserControls непосредственно в MainView, создайте два ContentControls, один с x:Name="LeftSide", а другой с x:name="RightSide". Это способ, основанный на представлении модели. Если вы хотите сделать это сначала просмотр, сохраните определения пользовательских элементов управления в своем MainView, но измените Bind.Model так, чтобы он указывал на новые свойства, которые вы создали, например Bind.Model="{Binding LeftSide}"

По сути, то, как у вас есть вещи, определяет .... привязки просто не указывают на нужные объекты более или менее. У вас есть Дирижер, который вам не нужен для этого. Вы можете оставить его, если хотите иметь какую-то навигационную архитектуру. Помните, что когда вы вызываете ActivateItem для Conductor, вы в основном меняете его свойство ActiveItem; одновременно может быть активна только одна модель. В приведенном выше случае вы активируете оба элемента, но только второй остается активным. Более того, на ваш взгляд, ActiveItem ничего не связывает.

Я надеюсь в этом есть смысл!

person EisenbergEffect    schedule 03.04.2012