WPF Extended ListBox doesn't find definition

89 Views Asked by At

have extended ListBox to give me a horizontal List Box, i.e, in XAML:

<ListBox x:Class="Renishaw.Inspire.InTheatreCompanion.View.HorizontalListBox"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Style="{x:Null}">

    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Name="ItemContainer" 
                                    Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>


</ListBox>

and in the code behind

public partial class HorizontalListBox : ListBox
   {
      public static readonly DependencyProperty IndentItemsProperty = DependencyProperty.Register(
         "IndentItems", typeof(double), typeof(HorizontalListBox), new PropertyMetadata(0.0, new PropertyChangedCallback(OnIndentItemsChanged)));

      public HorizontalListBox()
      {
         InitializeComponent();
      }

      public double IndentItems
      {
         get { return (double)GetValue(IndentItemsProperty); }
         set { SetValue(IndentItemsProperty, value); }
      }

      private static void OnIndentItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
         var horizontalListBox = (HorizontalListBox)d;
         var thickness = new Thickness((double)e.NewValue, 0, 0, 0);
         horizontalListBox.ItemContainer.Margin = thickness;
      }

      public static void SetIndentItems(DependencyObject obj, double thickness)
      {
         obj.SetValue(IndentItemsProperty, thickness);
      }

      public static double GetIndentItems(DependencyObject obj)
      {
         return (double)obj.GetValue(IndentItemsProperty);
      }

   }

where the dependency property IndentItems is suppose to allow me to indent the items a set amount by setting the margin of the VirtualizingStackPanel used to contain the items. However, attempting to build this throws an error telling me that "HorizonatlListBox does not contain a definition for 'ItemContainer'" even though it has been given that name in the xaml. Any ideas where I may be going wrong?

3

There are 3 best solutions below

0
On BEST ANSWER

Setting the Name of an element in a Template does not generate a member in the class that declares the Template, i.e. there is no ItemContainer member in your HorizontalListBox class.

Besides that, your IndentItems property seems to be redundant, because ListBox already has a Padding property:

<local:HorizontalListBox Padding="50,0,0,0" .../>

Now there is probably no more need for a derived HorizontalListBox, as you could just write this:

<ListBox Padding="50,0,0,0" ...>
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
<ListBox/>
1
On

How about using a converter for this?

<Window x:Class="ListBoxMargins.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ListBoxMargins"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.Resources>
        <local:StackConverter x:Key="StackConverter"/>
    </Grid.Resources>
    <ListBox ItemsSource="{Binding source}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel Name="ItemContainer" 
                                Orientation="Horizontal" 
                                Margin="{Binding RelativeSource={RelativeSource Self}, Path=IsKeyboardFocusWithin, Converter={StaticResource StackConverter}}"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Grid>

public partial class MainWindow : Window
{
    public ObservableCollection<string> source { get; set; }
    public MainWindow()
    {
        InitializeComponent();
        source = new ObservableCollection<string>();
        source.Add("Test element1");
        source.Add("Test element2");
        source.Add("Test element3");
        this.DataContext = this;
    }
}

I didn't do all the check here but in my test, the panel is indented.

public class StackConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        bool focused = (bool)value;

        if (focused)
        {
            return new Thickness(50);
        }
        else
        {
            return new Thickness(0);
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
0
On

You can meet your requirements much simpler than by creating new control:

<App.Resources>
    <ItemsPanelTemplate x:Key="HorizontalStackPanelTemplate">
        <VirtualizingStackPanel Orientation="Horizontal" />
    <ItemsPanelTemplate>
</App.Resources>

<ListBox ItemsSource="{Binding source}" Padding ="50,0,0,0"
         ItemsPanel="{StaticResource HorizontalStackPanelTemplate}" />