Create buttons programmatically with unique id - c#

I have created some buttons by first filling a class containing get/set methods and then using that info in XAML.
C#
List<MediaDetail> movies = new List<MediaDetail>();
...
...
MovieListView.ItemsSource = movies;
XAML
<Window.Resources>
<DataTemplate x:Key="ItemTemplate">
<WrapPanel Orientation="Vertical" Width="Auto">
<Button Width="200" Height="300" Click="SelectMovie_Click" Name ="NEED THIS TO BE DYNAMIC">
<Button.Template>
<ControlTemplate>
<Image Source="{Binding image}"/>
</ControlTemplate>
</Button.Template>
</Button>
<TextBlock Text="{Binding title}" HorizontalAlignment="Center"/>
</WrapPanel>
</DataTemplate>
</Window.Resources>
<ListView Name="MovieListView" ItemTemplate="{StaticResource ItemTemplate}" ItemsSource="{Binding Path = movies}" Margin="0,0,0,0" SelectionChanged="MovieListView_SelectionChanged" Grid.Row="1">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="5" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
However the issue is, I need each button to have a unique id. I read elsewhere that this can't be done in XAML but I'm not sure how or where in my C# code to create these buttons.

I think the most flexible solution here would be to define a behavior:
public class UniqueNameBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
base.OnAttached();
//assign unique name to the associated element, for example:
AssociatedObject.Name = Guid.NewGuid().ToString().Replace("-", null);
}
}
In XAML, attach this behavior to any element:
<Button>
<i:Interaction.Behaviors>
<local:UniqueNameBehavior/>
</i:Interaction.Behaviors>
</Button>
where xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" from System.Windows.Interactivity assembly.

Related

WPF Databinding ContextMenu of Button inside a DataTemplate inside an ItemsControl

I am trying to figure out how I can bind the ContextMenu of the Button that is being added in the ItemsControl I have. Basically, I'm wanting to be able to right click on a button and remove it from the observable collection that sits on my viewmodel. I understand that ContextMenu's are not part of the VisualTree, so using RelativeSource to walk up the tree to find my DataContext hasn't been useful to me.
The end goal of what I want to do is Bind the Command on the MenuItem to the RemoveCommand on my ViewModel and then pass in the Content property of the Button that you right click on so that I can remove it from the observable collection.
Any help on this would be greatly appreciated.
Model:
public class Preset
{
public string Name { get; set; }
}
ViewModel:
public class SettingsWindowViewModel
{
public ObservableCollection<Preset> MyPresets { get; } = new ObservableCollection<Preset>();
private ICommand _plusCommand;
public ICommand PlusCommand => _plusCommand ?? (_plusCommand = new DelegateCommand(AddPreset));
private ICommand _removeCommand;
public ICommand RemoveCommand => _removeCommand ?? (_removeCommand = new DelegateCommand<string>(RemovePreset));
private void AddPreset()
{
var count = MyPresets.Count;
MyPresets.Add(new Preset {Name = $"Preset{count+1}"});
}
private void RemovePreset(string name)
{
var preset = MyPresets.FirstOrDefault(x => string.Equals(x.Name, name, StringComparison.CurrentCultureIgnoreCase));
if (preset!= null)
{
MyPresets.Remove(preset);
}
}
}
XAML:
<Window x:Class="WpfTesting.Esper.Views.SettingsWindow"
x:Name="MainSettingsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:WpfTesting.Esper.ViewModels"
mc:Ignorable="d"
Title="SettingsWindow" Height="470" Width="612">
<Window.DataContext>
<viewModels:SettingsWindowViewModel/>
</Window.DataContext>
<Window.Resources>
<Style BasedOn="{StaticResource {x:Type MenuItem}}" TargetType="{x:Type MenuItem}" x:Key="PopupMenuItem">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Border>
<ContentPresenter ContentSource="Header"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="35"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<Button Width="70" Content="Load"/>
<Button Width="70" Content="Save As"/>
<ItemsControl ItemsSource="{Binding MyPresets}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Width="70" Content="{Binding Name}">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Style="{StaticResource PopupMenuItem}" Header="Remove">
<!--
I need to set up binding a Command to a method on the DataContext of the Window, and I need to pass in the Content of the Button that is the parent of the ContextMenu
-->
</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Width="20" Background="Transparent" BorderBrush="Transparent" Content="+" FontSize="21.333" HorizontalAlignment="Center" VerticalAlignment="Center" Command="{Binding PlusCommand}"/>
</StackPanel>
</Grid>
</Window>
Using WPF: Binding a ContextMenu to an MVVM Command as an introduction to what Tags can do, I figured out how to do what I was looking for by using multiple Tags to save the Context of what I was looking for.
I first made sure to give my window a x:Name
<Window x:Name="MainSettingsWindow"
Next, on the Button inside my DataTemplate of my ItemsControl, I set a Tag and set it to my Window
<ItemsControl ItemsSource="{Binding MyPresets}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Width="70" Content="{Binding Name}" Tag="{Binding ElementName=MainSettingsWindow}">
Next, in the ContextMenu, I seth the DataContext of the ContextMenu to the Tag I set on the Button, I also needed to create a Tag on the ContextMenu and point it back to the Content Property of the Button so that I can pass that into the CommandParameter
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Mode=Self}}" Tag="{Binding PlacementTarget.Content, RelativeSource={RelativeSource Mode=Self}}">
At this point, I can now bind my MenuItem correctly using the Command from my ViewModel and the Content Property from the Button
This is the final XAML for my ItemsControl:
<ItemsControl ItemsSource="{Binding MyPresets}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Width="70" Content="{Binding Name}" Tag="{Binding ElementName=MainSettingsWindow}">
<Button.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Mode=Self}}" Tag="{Binding PlacementTarget.Content, RelativeSource={RelativeSource Mode=Self}}">
<MenuItem Header="Remove"
Style="{StaticResource PopupMenuItem}"
Command="{Binding Path=DataContext.RemoveCommand}"
CommandParameter="{Binding Path=Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
One thing to note is that I had to change the CommandParameter on my ViewModel to take an Object instead of a String. The reason I did this was because I was getting an exception on the CanExecute method in my DelegateCommand
This is the exception I was getting:
Unable to cast object of type 'MS.Internal.NamedObject' to type 'System.String'.
I'm not sure exactly what's causing that exception to throw, but changing it to Object works ok for me.
I had basically a similar problem, and the solution I found was to use the Messenger class some MVVM frameworks like Devexpress or Mvvm Light have.
Basically you can register in a viewModel to listen for incoming messages. The class itself, at least in the Devexpress implementation works with weak references, so you may not even unregister message handlers and it will not cause memory leaks.
I had used this method for removing on right click tabs from a ObservableCollection, so it was similar to your scenario.
You can have a look here :
https://community.devexpress.com/blogs/wpf/archive/2013/12/13/devexpress-mvvm-framework-interaction-of-viewmodels-messenger.aspx
and here :
https://msdn.microsoft.com/en-us/magazine/jj694937.aspx

ItemsControl view doesn't updated when an item in ObservableCollection is updated

Introduction :
Hi, I meet a weird problem here. My ItemsControl doesn't update the view if I am updating the model (e.g. changing the value of IsSelected).
One of IsSelected purpose however, is, if the value is true, then the Background of the MusicalNotationBox (UserControl) is changed to blue, and if it's false then it's changed back to transparent.
A lot of person asked : Why not using trigger such as Focus for IsSelected? Because it's not just
for "visual" purposes. I have a Command which to change certain
Property (for example Note's Octave) of each MusicalNotation
object in VM's MusicalNotations, which IsSelected==true (support
multiselection), so I think I need IsSelected in the model. But this is not the problem here, so please no answer solely on this matter.
The problem is :
The model property is changed successfully (checked and verified), but it seems that the view isn't.
If I use the singular form of the UserControl, for e.g. <c:MusicalNotationBox DataContext={Binding}/> (ofc along with it's friends a.k.a correct properties in the VM), it synced perfectly. So, I'm not quite sure where the problem lies with the OC.
UPDATE : If I, for example create a MouseBinding that each time I click, then a new MusicalNotation added to the list, then, the view is also updated.
I have read several topic (google and here) on "Observable Collection
doesn't update the ItemsControl`, but still found no satisfying answer.
Here's my code (code may trimmed (...) for clarity sake) :
MODEL
public class MusicalNotation : ... INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
...
private bool _isSelected;
...
public bool IsSelected
{
get { return _isSelected; }
set { _isSelected = value; NotifyPropertyChanged("IsSelected"); }
}
...
public MusicalNotation()
{
...
IsSelected = false;
}
...
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
VIEW MODEL
public class MainWindowModelView : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<MusicalNotation> _musicalNotations;
...
public ObservableCollection<MusicalNotation> MusicalNotations
{
get { return _musicalNotations; }
set { _musicalNotations = value; NotifyPropertyChanged("MusicalNotations"); }
}
public MainWindowModelView()
{
...
MusicalNotations = new ObservableCollection<MusicalNotation>();
//Direct initialization for testing purpose
MusicalNotations.Add(MusicalNotation.GetEmptyNote(new TimeSignature(4, 4)));
MusicalNotations.Add(MusicalNotation.GetEmptyNote(new TimeSignature(4, 4)));
foreach (MusicalNotation item in MusicalNotations)
{
item.IsSelected = true;
}
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
VIEW
<Window ...>
<Window.Resources>
</Window.Resources>
<Window.InputBindings>
...
</Window.InputBindings>
<Grid>
...
<ItemsControl Grid.Column="0" Grid.Row="0" ItemsSource="{Binding MusicalNotations, Mode=OneWay}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<c:MusicalNotationBox/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Thanks.
UPDATE, My MusicalNotationBox XAML
<UserControl x:Class="NumberedMusicScoresUserControl.MusicalNotationBox"
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:NumberedMusicScoresUserControl.MusicalNotationBoxProperties"
mc:Ignorable="d">
<UserControl.Resources>
<local:DotConverter x:Key="DotConverter"/>
<local:NoteConverter x:Key="NoteConverter"/>
<local:AccidentalConverter x:Key="AccidentalConverter"/>
<local:IsSelectedConverter x:Key="IsSelectedConverter"/>
</UserControl.Resources>
<Grid x:Name="grid" Margin="10,5,10,5"
HorizontalAlignment="Center" VerticalAlignment="Center"
Background="{Binding Path=MusicalNotation.IsSelected, Converter={StaticResource IsSelectedConverter}, Mode=OneWay}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="1"
Text="b"
Visibility="{Binding Path=MusicalNotation.Accidental, Converter={StaticResource AccidentalConverter}, ConverterParameter=FL, Mode=OneWay}"
FontSize="15" FontFamily="CourierNew"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Path Grid.Column="1" Grid.Row="1" Stroke="Black" StrokeThickness="1" Stretch="Fill"
Visibility="{Binding Path=MusicalNotation.Accidental, Converter={StaticResource AccidentalConverter}, ConverterParameter=SP, Mode=OneWay}" >
<Path.Data>
<LineGeometry StartPoint="1,0" EndPoint="0,1">
<LineGeometry.Transform>
<RotateTransform CenterX="0" CenterY="0" Angle="30"/>
</LineGeometry.Transform>
</LineGeometry>
</Path.Data>
</Path>
<TextBlock Grid.Column="1" Grid.Row="1"
Text="{Binding Path=MusicalNotation.Note, Converter={StaticResource NoteConverter}, Mode=OneWay}"
FontSize="15" FontFamily="CourierNew"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="2.5,0,2.5,0"/>
<ItemsControl Grid.Column="1" Grid.Row="0"
ItemsSource="{Binding Path=MusicalNotation.Octave, Converter={StaticResource DotConverter}, ConverterParameter=TOP, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse HorizontalAlignment="Center" VerticalAlignment="Top"
Margin="{Binding Margin}" Fill="{Binding Fill}"
Width="{Binding Diameter}" Height="{Binding Diameter}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Grid.Column="1" Grid.Row="2"
ItemsSource="{Binding Path=MusicalNotation.Octave, Converter={StaticResource DotConverter}, ConverterParameter=BOT, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse HorizontalAlignment="Center" VerticalAlignment="Bottom"
Margin="{Binding Margin}" Fill="{Binding Fill}"
Width="{Binding Diameter}" Height="{Binding Diameter}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Grid.Column="2" Grid.Row="1"
ItemsSource="{Binding Path=MusicalNotation.Dot, Converter={StaticResource DotConverter}, ConverterParameter=RIGHT, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse HorizontalAlignment="Left" VerticalAlignment="Center"
Margin="{Binding Margin}" Fill="{Binding Fill}"
Width="{Binding Diameter}" Height="{Binding Diameter}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
(I didn't include it since, I think, if the "singular" one is correct, then my UserControl is correct as well. Might be wrong though.)
The DataContext for your user control is the MusicalNotation object, so while binding instead of using
Background="{Binding Path=MusicalNotation.IsSelected, Converter={StaticResource ....
just use
Background="{Binding Path=IsSelected, Converter={StaticResource ....
Drop the MusicalNotation prefix from the bindings.
{Binding Path=IsSelected, ...
As you haven't specified any binding for the selected item or for the IsSelected in your xaml, that's why view is not being updated when the property is changed in the VM. For updating the view you will have to provide a binding for SelectedItem property of ItemsControl.

scope of element names in XAML

I'm trying to name and then set a DataContext for a ComboBox that's embedded within an ItemsControl.
In my main Window, I can access the ItemsControl by name but not any of the elements within the ItemsControl.
public MainWindow()
{
InitializeComponent();
SList.DataContext = App.SCList; //this is valid
StS.DataContext = App.STList; //this is not
}
And here's the XAML code. I can access SList from within the program but not "StS" or "SPanel1". The compiler error is:
"The name 'StS' does not exist in the current context"
Note that I've tried both "Name" and "x:Name"
<ScrollViewer VerticalScrollBarVisibility="Auto" >
<ItemsControl Name ="SList" ItemsSource ="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Margin="12"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="3" CornerRadius="5" Margin="8,8" ClipToBounds="True" Background="Beige">
<StackPanel Name="SPanel1">
<StackPanel Orientation="Horizontal">
<Label Content="S Type"/>
<ComboBox Name ="StS" ItemsSource="{Binding Path=ShipType.TypeName, Mode=TwoWay}" DataContext="STList">
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Class Name"/>
<TextBox Text="{Binding Path = Name, Mode=TwoWay}" HorizontalAlignment="Center" FontWeight="Bold" />
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>

Different Object-Types in Grid- or ListView

I'm currently trying to figure out how to show different types of objects in a GridView, look at this Pic for example:
the last element on the right side is different than the other elements, so if i bind an observablecollection to the GridView, how can i say that the last element is shown up in anohter layout.
currently I'm using this XAML-Code
<GridView x:Name="startView" ItemsSource="{Binding}" Grid.Column="1" Grid.Row="2" SelectionMode="None" Width="Auto">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="DetailTitle" Height="74" Text="{Binding Title}" />
<Image x:Name="Image" Height="Auto" Width="Auto" Margin="0" Stretch="None" Source="{Binding LocalCoverUrl}" Visibility="Collapsed" />
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal" MaximumRowsOrColumns="2" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
and this Code in the Back:
ObservableCollection<Movie> recentlyStarted = await Api.RecentlyStarted(3);
startView.DataContext = recentlyStarted;
but I have currently no clue how to let the last element show up in a different style
The easy way would be to have the two types of object as different classes (e.g. MoviePicStyle + MoviePlainStyle. Then move your DataTemplate out of the GridView, so that each object is picked up by type,
e.g.
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModel:MoviePicStyle}">
<StackPanel>
<TextBlock x:Name="DetailTitle" Height="74" Text="{Binding Title}" />
<Image x:Name="Image" Height="Auto" Width="Auto" Margin="0" Stretch="None" Source="{Binding LocalCoverUrl}" Visibility="Collapsed" />
</StackPanel>
<DataTemplate DataType="{x:Type ViewModel:MoviePlainStyle}">
...Different View...
</DataTemplate>
</Window.Resources>
<GridView...
Use template selector property of gridview and depending upon the type of object select the template. I did the same in my project. you need to write your own DataTemplateSelector.
I referred below link
http://babaandthepigman.wordpress.com/2012/02/08/datatemplateselector-winrt/

ItemsControl with horizontal orientation

Do you know any controls inherited from the ItemsControl that have horizontal orientation of items?
Simply change the panel used to host the items:
<ItemsControl ...>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
While the promoted answer is great, here's an alternative if you want the items to stretch.
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
This is an example of how to do horizontal scrolling within an ItemsControl.
Firstly the main window viewmodel class used to get/set the list of items we wish to display.
MainWindowViewModel.cs
using System.Collections.Generic;
namespace ItemsControl
{
public class Item
{
public Item(string title)
{
Title = title;
}
public string Title { get; set; }
}
public class MainWindowViewModel
{
public MainWindowViewModel()
{
Titles = new List<Item>()
{
new Item("Slide 1"),
new Item("Slide 2"),
new Item("Slide 3"),
new Item("Slide 4"),
new Item("Slide 5"),
new Item("Slide 6"),
new Item("Slide 7"),
new Item("Slide 8"),
};
}
public List<Item> Titles { get; set; }
}
}
The main window xaml for the view:
MainWindow.xaml
<Window x:Class="ItemsControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ItemsControl"
mc:Ignorable="d"
Title="MainWindow" Height="400" Width="400">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid Margin="5">
<ScrollViewer
VerticalScrollBarVisibility="Disabled"
HorizontalScrollBarVisibility="Auto">
<ItemsControl
x:Name="SearchResultList"
ItemsSource="{Binding Titles}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border
Margin="5"
BorderThickness="1"
BorderBrush="Aqua">
<TextBlock
Text="{Binding Title}"
HorizontalAlignment="Center"
VerticalAlignment="Top"
FontSize="12"
TextWrapping="Wrap"
TextAlignment="Center"
FontWeight="DemiBold"
Width="150"
Height="150" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Window>
Depending on how high/wide your client area is, this will result in this kind of layout, overflow items scrolled horizontally:
More details can be found at this blog link, including an example on how to do the scrolling vertically:
http://www.technical-recipes.com/2017/how-to-orient-wrappanel-items-within-itemscontrol-lists-vertically-and-horizontally/
The top answer is good, but I couldn't get it to work with UserControls. If you need UserControls, this should help.
ItemsControl with Horizontal Usercontrols
My Version:
<Window.Resources>
<DataTemplate x:Key="ItemTemplate2">
<StackPanel>
<uc:MyUserControl MinWidth="20" BorderBrush="Black" BorderThickness="0.1" />
</StackPanel>
</DataTemplate>
<ItemsPanelTemplate x:Key="ItemsPanelTemplate1">
<StackPanel Orientation="Horizontal" Margin="0,0,0,0"/>
</ItemsPanelTemplate>
</Window.Resources>
<StackPanel>
<ItemsControl x:Name="list_MyControls"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="0,8,0,0"
ItemTemplate="{StaticResource ItemTemplate2}"
ItemsPanel="{StaticResource ItemsPanelTemplate1}" />
</StackPanel>
To bind to data, you will need to add an ItemsSource to the ItemsControl in the XAML or code behind. Also note that uc: would be the xmlns:uc="NamespaceOfMyControl" declared at the top of the file.
For a long list with hundreds or even thousands of items, you should better use VirtualizingStackPanel to avoid performance issues.

Categories