Caliburn.Micro заставляет его связывать UserControls в MainView с их ViewModels - PullRequest
13 голосов
/ 03 апреля 2012

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

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

Теперь я поместил UserControls в папку Views вместе с MainView и назвал их LeftSideControlView.xaml и RightSideControlView.xaml.Соответствующие ViewModel находятся в папке 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>

Я добавил видовые модели и их интерфейсы в 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, чтобы сказать ему, чтобы загрузить эти 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!"; }
      }
   }
}

1 Ответ

23 голосов
/ 03 апреля 2012

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

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

Надеюсь, это имеет смысл!

...