Search code examples
c#wpfmockinguser-controlsitemscontrol

User control inside ItemsControl doesn't populate with mocked properties


I'm making a demo app where a simple class Fruit with two properties Name and Color is displayed in a FruitUC with a field for each. In a ProduceVM class I fill an ObservableCollection SupportedFruits with Fruit instances and bind the ProduceVM instance to another user control, FruitView, where an ItemsControl displays each element of SupportedFruits. I also have a MockProduceVM subclass of ProduceVM that creates adds 3 Fruit objects to SupportedFruits that I should be able to see at design time.

Everything works fine at runtime, but at design time the FruitUCs are empty. If in the ItemsControl I have TextBoxes that show the Name and Color of each Fruit, they mock up just fine. But each FruitUC supposedly bound to the same data behaves as if both properties are blank strings. What am I missing for the FruitUC in the ItemsControl of my FruitView? Thanks in advance and sorry for some of this formatting...

Fruit:

public class Fruit : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;

private string _name;
private string _color;

public string Name {
  get { return _name; }
  set {
    if (_name != value) {
      _name = value;
      NotifyListeners();
    }
  }
}

public string Color {
  get { return _color; }
  set {
    if (_color != value) {
      _color = value;
      NotifyListeners();
    }
  }
}

private void NotifyListeners([CallerMemberName] string propertyName = "") {
  try {
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  } catch (Exception anException) {
    throw anException;
  }
}

FruitUC.xaml:

<UserControl x:Class="WPFInAction.FruitUC"
         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" 
         xmlns:local="clr-namespace:WPFInAction"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800">
<Grid Background="LightGray" d:DataContext="{d:DesignInstance Type=local:Fruit, IsDesignTimeCreatable=True}">
    <Grid.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="FontSize" Value="20" />
            <Setter Property="HorizontalAlignment" Value="Right" />
            <Setter Property="Margin" Value="5,1,5,0" />
        </Style>
        <Style TargetType="TextBox">
            <Setter Property="MinWidth" Value="80" />
            <Setter Property="Height" Value="30" />
            <Setter Property="FontSize" Value="20" />
        </Style>
    </Grid.Resources>
    <Grid.RowDefinitions>
        <RowDefinition Height="10" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <TextBlock x:Name="lblFruitName" Text="Name:" Grid.Row="1" />
    <TextBox x:Name="txtFruitName" Text="{Binding Name}" Grid.Row="1" Grid.Column="1" />
    <TextBlock x:Name="lblFruitColor" Text="Color:" Grid.Row="2" />
    <TextBox x:Name="txtFruitColor" Text="{Binding Color}" Grid.Row="2" Grid.Column="1" />
</Grid>

FruitUC.xaml.cs:

public partial class FruitUC : UserControl {

public FruitUC() {
  InitializeComponent();
}
}

ProduceVM:

public class ProduceVM {
public ObservableCollection<Fruit> SupportedFruits { get; set; }

public ProduceVM() {
  SupportedFruits = new ObservableCollection<Fruit>();
    private static readonly string[] _fruitNames = { "Apple", "Orange", "Banana", "Avocado", "Blueberry", "Grape" };
private static readonly string[] _fruitColors = { "Red", "Orange", "Yellow", "Green", "Blue", "Purple" };

  if (!DesignerProperties.GetIsInDesignMode(new System.Windows.DependencyObject())) {
    for (var f = 0; f < _fruitNames.Length; f++) {
      SupportedFruits.Add(new Fruit { Name = _fruitNames[f], Color = _fruitColors[f] });
    }
  }
}

}

MockProduceVM:

public class MockProduceVM : ProduceVM {
public MockProduceVM() : base() {
  SupportedFruits.Add(new Fruit { Name ="Grape", Color = "Red" });
  SupportedFruits.Add(new Fruit { Name ="Apple", Color = "Yellow" });
  SupportedFruits.Add(new Fruit { Name ="Banana", Color = "Green" });
}
}

FruitsView.xaml:

<UserControl x:Class="WPFInAction.FruitsView"
         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" 
         xmlns:local="clr-namespace:WPFInAction"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800">
<DockPanel d:DataContext="{d:DesignInstance Type=local:MockProduceVM, IsDesignTimeCreatable=True}" Background="AliceBlue">
    <ItemsControl ItemsSource="{Binding SupportedFruits}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Vertical"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <WrapPanel Orientation="Vertical">
                    <local:FruitUC />
                    <TextBox x:Name="txtFruitName" Text="{Binding Name}" Width="70" />
                    <TextBox x:Name="txtFruitColor" Text="{Binding Color}" Width="70" Margin="10,0,0,10" />
                </WrapPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</DockPanel>

FruitsView.xaml.cs:

  public partial class FruitsView : UserControl {
public FruitsView() {
  InitializeComponent();
  DataContext = new ProduceVM();
}
}

At runtime: enter image description here

At design/mock time:

enter image description here

EDIT: I notice that if I make a change to the MockProduceVM, then build, then go to FruitsView.xaml, I see the property values as set, then after a split second they empty out.

EDIT 2: If I replace the FruitUC inside FruitsView with the contents of FruitUC the Name and Color fields still appear blank.


Solution

  • In FreuitUC.xaml you are overriding the Datacontext of the Grid for the Desgin-Time with

    <Grid Background="LightGray" d:DataContext="{d:DesignInstance Type=local:Fruit, IsDesignTimeCreatable=True}">

    So inside that Grid the DataContext is no longer on the collection item of the SupportedFruits collection.

    Remove the DataContext override and it should be fine.

    enter image description here