user1670340
user1670340

Reputation: 159

Customize ListBoxItems using Template WPF

This question is about lay outing in XAML in WPF. I have a specific layout to follow. The ListBoxItems count tells how many images it would display. The images comes from a collection list which is has properties Data and Text. Each image has text above to it which is bind to Text. The Data holds the image source/path values. This could be dynamic values but for this example list.

  A   |   B       C  |  D       E  |  F       G   |  H      I   |   J
Apple |  Boy     Cat | Dog     Egg | Fan     Goat | Hen    Ice  | Jelly 

The Apple and Boy and other names here are images. My main problem is how can I manage to have this layout. In which I need to group it by 2 images like A and B but separated with | (a separator block image). Maximum pair of images to display per row is 5. The next set of images will be put in the next row.

My current test code:

`
    public class ViewModel
    {
        public string Text { get; set; }
        public string FilePath { get; set; }
    }

    /// 
    /// Interaction logic for MainWindow.xaml
    /// 
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            List listItems = new List();
            listItems.Add(new ViewModel() { Text = "A", Data = "ListBoxTest;component/Images/Apple.png" });
            listItems.Add(new ViewModel() { Text = "B", Data = "ListBoxTest;component/Images/Boy.png" });
            listItems.Add(new ViewModel() { Text = "C", Data = "ListBoxTest;component/Images/Cat.png" });
            listItems.Add(new ViewModel() { Text = "D", Data = "ListBoxTest;component/Images/Dog.png" });
            listItems.Add(new ViewModel() { Text = "E", Data = "ListBoxTest;component/Images/Egg.png" });
            listItems.Add(new ViewModel() { Text = "F", Data = "ListBoxTest;component/Images/Fan.png" });
            listItems.Add(new ViewModel() { Text = "G", Data = "ListBoxTest;component/Images/Goat.png" });
            listItems.Add(new ViewModel() { Text = "H", Data = "ListBoxTest;component/Images/Hen.png" });
            listItems.Add(new ViewModel() { Text = "I", Data = "ListBoxTest;component/Images/Ice.png" });
            listItems.Add(new ViewModel() { Text = "J", Data = "ListBoxTest;component/Images/Jelly.png" });

            myListBox.ItemsSource = listItems;
        }
    }
<Style x:Key="listBoxItemStyle"
       TargetType="ListBoxItem">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <StackPanel>
                    <Grid>
                        <TextBlock Text="{Binding Text}" Margin="30" />
                        <Image Name="pumpImage"
                               Source="{Binding Data}" 
                               Width="100" 
                               Height="100" />
                    </Grid>
                </StackPanel>
             </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Please share your thoughts or ideas on how to achieve this. Thank you.

Upvotes: 0

Views: 1338

Answers (1)

M.E.
M.E.

Reputation: 2929

You can do the following steps:

1. Create a ViewModel for a pair of items

class PairViewModel
{
  public string LeftText { get; set; }
  public string LeftData { get; set; }

  public string RightText { get; set; }
  public string RightData { get; set; }
}

2. Create a control to style one single pair of items, for example like this:

<UserControl x:Class="WpfApplication2.PairControl"
             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:WpfApplication"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" d:DataContext="{d:DesignInstance local:PairViewModel}">
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding LeftText}" />
    <Image Grid.Row="1" Grid.Column="0" Source="{Binding LeftData}" />

    <Separator Grid.Column="1" Grid.RowSpan="2" Grid.Row="0" Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" />

    <TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding RightText}" />
    <Image Grid.Row="1" Grid.Column="2" Source="{Binding RightData}" />
  </Grid>
</UserControl>

3. In your MainWindow XAML, create a ListBox with a UniformGrid ItemsPanelTemplate

With the UniformGrid you control the maximum number of columns.

<Grid>
  <ListBox x:Name="myListBox">
    <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
        <UniformGrid Columns="5" />
      </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
  </ListBox>
</Grid>

4. Define a DataTemplate in your App resources or in your Window resources:

<Window.Resources>
  <DataTemplate DataType="{x:Type local:PairViewModel}">
    <local:PairControl />
  </DataTemplate>
</Window.Resources>

5. Fill your PairViewModel with data (example) :

 List<PairViewModel> pairs = new List<PairViewModel>();

 pairs.Add(new PairViewModel {LeftText = "A", LeftData = "Apple.png", RightText = "B", RightData = "Boy.png"});
 pairs.Add(new PairViewModel {LeftText = "C", LeftData = "Apple.png", RightText = "D", RightData = "Boy.png"});
 pairs.Add(new PairViewModel {LeftText = "E", LeftData = "Apple.png", RightText = "F", RightData = "Boy.png"});
 pairs.Add(new PairViewModel {LeftText = "G", LeftData = "Apple.png", RightText = "H", RightData = "Boy.png"});
 pairs.Add(new PairViewModel {LeftText = "I", LeftData = "Apple.png", RightText = "J", RightData = "Boy.png"});
 pairs.Add(new PairViewModel {LeftText = "K", LeftData = "Apple.png", RightText = "L", RightData = "Boy.png"});

 myListBox.ItemsSource = pairs;

You might need to adjust some styling, but this are basically the steps you need.

Upvotes: 1

Related Questions