0

My application consists of Categories that contain many Products.

Given a Category, I want to display an element for each of its Products:

<UserControl x:Class="MyApp.CategoryControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyApp"
    >
    <StackPanel>
        <TextBlock>Products:</TextBlock>
        <ItemsControl ItemsSource="{Binding Path=Products}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <local:ProductControl Product="{Binding}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</UserControl>
public partial class CategoryControl : UserControl
{
    public Product[] Products { get; set; }
}

...wherein it displays some information about the Product, and shows/collapses additional information when the Product name is clicked:

<UserControl x:Class="MyApp.ProductControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyApp"
    >
    <StackPanel>
        <TextBlock MouseDown="ProductName_Click" Text="{Binding Path=Product.Name}" />
        <TextBlock
            Text="{Binding Path=Product.Description}"
            Visibility="{Binding Path=IsCollapsed, Converter={local:BooleanToVisiblity}}"
            />
    </StackPanel>
</UserControl>
public partial class ProductControl : UserControl
{
    public bool IsCollapsed { get; set; } = true;

    public Product Product
    {
        get => (Product)GetValue(ProductProperty);
        set => SetValue(ProductProperty, value);
    }
    public static readonly DependencyProperty ProductProperty = DependencyProperty.Register(
        "Product",
        typeof(Product),
        typeof(FrameworkElement)
        );

    public ProductControl ()
    {
        DataContext = this;
        InitializeComponent();
    }

    public void ProductName_Click(object sender, EventArgs e) {
        IsCollapsed = !IsCollapsed;
        PropertyChanged("IsCollapsed");
    }
}

However this produces the following two errors, once each per Product:

System.Windows.Data Error: 1 : Cannot create default converter to perform 'one-way' conversions between types 'MyApp.ProductControl' and 'MyApp.Product'. Consider using Converter property of Binding. BindingExpression:Path=; DataItem='ProductControl' (Name=''); target element is 'ProductControl' (Name=''); target property is 'Product' (type 'Product')
System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='MyApp.ProductControl' BindingExpression:Path=; DataItem='ProductControl' (Name=''); target element is 'ProductControl' (Name=''); target property is 'Product' (type 'Product')

What am I doing wrong?

RobertAKARobin
  • 3,933
  • 3
  • 24
  • 46
  • 1
    A UserControl must not explicitly set its own DataContext, as this breaks the standard data binding of its properties. – Clemens Aug 22 '23 at 05:06
  • Besides that, the expression `Converter={local:BooleanToVisiblity}` is invalid. Declare the converter as resource and write `Converter={StaticResource theResourceKey}`. – Clemens Aug 22 '23 at 05:11
  • 1
    It is also unclear how `PropertyChanged("IsCollapsed")` is supposed to work. Your UserControl does not (and should not) implement INotifyPropertyChanged. `IsCollapsed` should instead be a dependency property. – Clemens Aug 22 '23 at 05:14
  • Sorry, I tried to type up a contrived example instead of pasting my actual code and clearly failed miserably, haha! Thanks for your response. – RobertAKARobin Aug 22 '23 at 12:58

0 Answers0