Search code examples
wpfmvvmprismprism-4

Binding from MVVM to View not working in Prism


I'm new to Prism, but I have successfully built several WPF/Mvvm-Light applications. I'm using ViewModel-first instaciation for each View/ViewModel pair. The views are all loaded and deactivated when the application opens. Views are activated as a result of catching an aggregate event aimed at them. This is the first view I've tried to bind to data in a ViewModel. The view displays as expected, except that my listbox is never populated. Only the outline of the listbox is visible. If I change the background color of the listbox, the color of the empty listbox is changed. The ViewModel property has eight rows but none of them are visible. I am able to display hardcoded items in the list box. I know that the view model is loading into the view as the data context, since another textblock is able to bind to a ViewModel property It must be something broken in my listbox xaml. Here is some xaml to review:

  <UserControl
     x:Class="DxStudioSelect.View.DxStudioFindView"
     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" 
  >
     <UserControl.Resources>
        <DataTemplate x:Key="DxStudioListTemplate">
           <TextBlock Text="{Binding Path=FriendlyForkName}"/>
        </DataTemplate>
     </UserControl.Resources>
     <Grid>
        <Grid.ColumnDefinitions>
           <ColumnDefinition Width="*"/>
           <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <ListBox
           Grid.Column="0"
           ItemsSource="{Binding DatabaseInstanceList}"
           ItemTemplate="{StaticResource DxStudioListTemplate}"
        />
        <TextBlock Text="{Binding Path=PageName}" Grid.Column="1" FontSize="32" Foreground="Green" TextAlignment="Right"/>
     </Grid>
  </UserControl>

Here is the code-behind:

  public partial class DxStudioFindView : UserControl, IDxStudioFindView {
     public DxStudioFindView() {
        InitializeComponent();
     }

     public IViewModel ViewModel {
        get { return (IDxStudioFindViewModel)DataContext; }
        set { DataContext = value; }
     }
  }

Here is the ViewModel:

  private readonly IEventAggregator _eventAggregator;
  private readonly IUnityContainer _unityContainer;
  private readonly IRegionManager _regionManager;
  private readonly string _dxStudioDatabaseName;
  private readonly HeaderUpdatePayload _headerUpdatePayload = new HeaderUpdatePayload("DxStudio", "Select DxStudio Instance");

  public DxStudioFindViewModel(IUnityContainer unityContainer, IRegionManager regionManager, IEventAggregator eventAggregator, IDxStudioFindView view)
     : base(view) {
     _unityContainer = unityContainer;
     _regionManager = regionManager;
     _eventAggregator = eventAggregator;
     View.ViewModel = this;

     if(IsInDesignMode) {

        //Design-time, so show fake data
        DesignTimeDataLoad();
     } else {

        //Run-time, so do the real stuff
        DesignTimeDataLoad();
        _dxStudioDatabaseName = LiteralString.DxStudioDatabaseNameTest;

        _eventAggregator.GetEvent<ViewChangeRequestEvent>().Subscribe(DxStudioInstanceChangeRequest, ThreadOption.UIThread, false, target => target.TargetView == LiteralString.DxStudioFind);
     }
  }


  public string PageName { get; set; }
  //public string PageName { get { return "Find DxStudio Instance"; } }

  private ObservableCollection<IDxStudioInstanceDto> _dxStudioInstanceList = null;
  public ObservableCollection<IDxStudioInstanceDto> DxStudioInstanceList {
     get { return _dxStudioInstanceList; }
     set {
        _dxStudioInstanceList = value;
        OnPropertyChanged("DxStudioInstanceList");
     }
  }

  private void DxStudioInstanceChangeRequest(ViewChangeRequestPayload payload) {
     var region = _regionManager.Regions[RegionNames.Content];
     region.Activate(View);

     _eventAggregator.GetEvent<ViewChangedHeaderEvent>().Publish(_headerUpdatePayload);

     var footerUpdatePayload = new FooterUpdatePayload(FooterDisplayMode.DxStudioSelect, _dxStudioDatabaseName, payload.TargetBackDatabase, payload.TargetBack, string.Empty, LiteralString.ToolboxStart);
     _eventAggregator.GetEvent<ViewChangedFooterEvent>().Publish(footerUpdatePayload);
  }

  private void DesignTimeDataLoad() {
     PageName = "Find DxStudio Instance";
     DxStudioInstanceList = new ObservableCollection<IDxStudioInstanceDto>() {
        new DxStudioInstanceDto("Instance1"),
        new DxStudioInstanceDto("Instance2"),
        new DxStudioInstanceDto("Instance3"),
        new DxStudioInstanceDto("Instance4"),
        new DxStudioInstanceDto("Instance5"),
        new DxStudioInstanceDto("Instance6"),
        new DxStudioInstanceDto("Instance7"),
        new DxStudioInstanceDto("Instance8"),
     };
  }

And here is the data transfer object:

public class DxStudioInstanceDto : IDxStudioInstanceDto {
  public string FriendlyForkName { get; private set; }

  public DxStudioInstanceDto(string friendlyForkName) { FriendlyForkName = friendlyForkName; }
}

Since I'm completely out of ideas, any suggestion would be helpful. Thanks


Solution

  • Your list is binding to ItemsSource="{Binding DatabaseInstanceList}" but your view model has the property DxStudioInstanceList.