2
votes

I'm new to Caliburn Micro so I'm sure there's something easy that I' missing here.

I have a top-level Shell View:

<Window x:Class="LotRunPlotGrid.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:local="clr-namespace:LotRunPlotGrid.Views"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        >
    <Grid>
        <local:LotRunPlotGridView />
    </Grid>
</Window>

and it's associated view model:

namespace LotRunPlotGrid
{
    public class ShellViewModel : IShell {}
}

Then I have a user control defined as:

<UserControl x:Class="LotRunPlotGrid.Views.LotRunPlotGridView"
             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:converter="clr-namespace:LotRunPlotGrid.Converters"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:vm="clr-namespace:LotRunPlotGrid.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="900"
             d:DataContext="{d:DesignInstance Type=vm:LotRunPlotGridViewModel, IsDesignTimeCreatable=True}">
    <UserControl.Resources>
        <converter:LotRunItemValueToColorConverter x:Key="ColorConverter"/>
        <Style x:Key="LotRunButtonStyle" TargetType="Button">
            <Setter Property="Width" Value="Auto"/>
            <Setter Property="Height" Value="{Binding ActualWidth, RelativeSource={RelativeSource Self}}"/>
            <Setter Property="BorderBrush" Value="Black"/>
            <Setter Property="BorderThickness" Value="2"/>
            <Setter Property="FontFamily" Value="Segoe UI"/>
            <Setter Property="FontSize" Value="20"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="Content" Value="{Binding LotID}"/>
        </Style>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row ="0" Text="Lot Run Plot Grid View" FontSize="20" FontFamily="Segoe UI"/>
        <ItemsControl Grid.Row="1" ItemsSource="{Binding LotRunItemsCollection}" Margin="0,0,-200,0" HorizontalAlignment="Left" Width="893">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid Columns="10"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button x:Name="LotRunItemButton" Style="{StaticResource LotRunButtonStyle}">
                        <Button.Background>
                            <MultiBinding Converter="{StaticResource ColorConverter}">
                                <Binding Path="LotRunDataDisplayMode" />
                                <Binding Path="LotRunItemValue"/>
                            </MultiBinding>
                        </Button.Background>
                    </Button>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</UserControl>

and it's associated view model ....

using Caliburn.Micro;
using System.Collections.ObjectModel;

namespace LotRunPlotGrid.ViewModels
{
    public class LotRunPlotGridViewModel : PropertyChangedBase
    {
        private ObservableCollection<LotRunItem> _lotRunItemsCollection = new ObservableCollection<LotRunItem>();
        public ObservableCollection<LotRunItem> LotRunItemsCollection
        {
            get { return _lotRunItemsCollection; }
            set { _lotRunItemsCollection = value; }
        }

        private int _numDisplayedColumns;
        public int NumDisplayedColumns
        {
            get { return _numDisplayedColumns; }
            set { _numDisplayedColumns = value; }
        }

        private int _numDisplayedRows;
        public int NumDisplayedRows
        {
            get { return _numDisplayedRows; }
            set { _numDisplayedRows = value; }
        }

        private int _lotRunDataDisplayMode;
        public int LotRunDataDisplayMode
        {
            get { return _lotRunDataDisplayMode; }
            set { _lotRunDataDisplayMode = value; }
        }


        public LotRunPlotGridViewModel()
        {
            LotRunItemsCollection.Add(new LotRunItem() { LotId = "Lot1", LotRunItemValue = "55", LotRunItemColor = "#FF05579" });
            LotRunItemsCollection.Add(new LotRunItem() { LotId = "Lot2", LotRunItemValue = "45", LotRunItemColor = "#FF05579" });
            LotRunItemsCollection.Add(new LotRunItem() { LotId = "Lot3", LotRunItemValue = "35", LotRunItemColor = "#FF05579" });
            LotRunItemsCollection.Add(new LotRunItem() { LotId = "Lot4", LotRunItemValue = "25", LotRunItemColor = "#FF05579" });
            LotRunItemsCollection.Add(new LotRunItem() { LotId = "Lot5", LotRunItemValue = "15", LotRunItemColor = "#FF05579" });
        }
    }
}

The issue I'm having is that the Items Control does not show up because I get a binding error stating that the LotRunItemsCollection is not found in the ShellViewModel, when as displayed above, LotRunItemsCollection is a member of the LotRunPlotGridViewModel.

So what am I missing here regarding binding the LotRunPlotGridViewModel to the LotRunPlotGridView so that LotRunItemsCollection is found in the correct view model?

Thanks for any help!

1
When in doubt you can always add a <Label Content="{Binding}"/> to try understand where you are. Or, you can debug your WPF tree with Live Visual Tree on VS2017, else use snoopwpf.codeplex.com. - aybe

1 Answers

0
votes

You get that message because the control has no backing data context with that property name.

Create a property in the shell view model like below

namespace LotRunPlotGrid
{
    public class ShellViewModel : PropertyChangedBase, IShell {
        private LotRunPlotGridViewModel myGrid = new LotRunPlotGridViewModel();

        public LotRunPlotGridViewModel MyGrid {
            get { return myGrid; }
            set {
                myGrid = value;
                NotifyOfPropertyChanged();
            }
        }
    }
}

and then in the view you can name the user control to match the property name

<Window x:Class="LotRunPlotGrid.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:local="clr-namespace:LotRunPlotGrid.Views"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        >
    <Grid>
        <local:LotRunPlotGridView x:Name="MyGrid" />
    </Grid>
</Window>

The framework will by convention Bind the MyGrid property to the local:LotRunPlotGridView as its data context.

If you do not want to tie the user control directly to the shell the framework is smart enough to look for the view based on the bound view model.

For example if the shell has the following

<Window x:Class="LotRunPlotGrid.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        >
    <Grid>
        <ContentControl x:Name="MyGrid" />
    </Grid>
</Window>

Note the local namespace was removed. The framework when binding the control will notice that the content is empty and search for the matching view of the bound property using naming conventions.