Reputation: 13
as I'm fairly new to C# and WPF I just can't figure out how to do this. I have a form that should show 151 images (all pokemon generation 1 sprites) in a form. The way I've done it now is that it shows the same image 151 times instead of all images just once. The code I wrote for this is as follow:
public partial class PokeGame : Window
{
BitmapImage carBitmap = new BitmapImage(new Uri("pack://application:,,,/Images/All_Sprites/001.png", UriKind.Absolute));
{
InitializeComponent();
int imgCount = 151;
int left = 0;
int top = 0;
List<Image> imageList = new List<Image>();
for (int i = 0; i < imgCount; i++)
{
if(i % 10 == 0)
{
if (i != 0)
{
top += 175;
left = 0;
} else
{
top = 0;
left = 0;
}
}
Image img_ding = new Image();
img_ding.Source = carBitmap;
img_ding.Height = 150;
img_ding.Width = 150;
img_ding.Margin = new Thickness(left, top ,0 ,0);
imageList.Add(img_ding);
left += 175;
}
int j = 0;
foreach (Image img in imageList)
{
imageCanvas.Children.Add(img);
j++;
}
}
As you can see there's probably lots of room for improvement in my code. However, my question is: How can I make it so that it doesn't display the same image 151 times but all images (sprite001.png, sprite002.png, sprite003.png, etc.)?
Upvotes: 1
Views: 1457
Reputation: 128146
Instead of programmatically adding Image controls to a Canvas, write this XAML:
<ItemsControl x:Name="images">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="10"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Width="150" Height="150" Source="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Probably add some Margin
to the Image control in the DataTemplate.
In code behind, add one line to the constructor of your MainWindow:
using System.Linq;
...
public MainWindow()
{
InitializeComponent();
images.ItemsSource = Enumerable
.Range(1, 151)
.Select(i => string.Format("pack://application:,,,/Images/{0:000}.png", i));
}
Now you might want to create a proper view model, where you would have a collection-type property for your images, like
public class ViewModel
{
public ObservableCollection<string> Images { get; }
= new ObservableCollection<string>(Enumerable
.Range(1, 151)
.Select(i => string.Format("pack://application:,,,/Images/{0:000}.png", i)));
}
You would then assign the Window's DataContext to an instance of the view model, and bind to the collection property like this:
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
XAML
<ItemsControl ItemsSource="{Binding Images}">
...
</ItemsControl>
Upvotes: 5
Reputation: 37066
You create carBitmap
exactly once, outside the loop, and use it every time. Create a new one for each image instead.
Image img_ding = new Image();
BitmapImage carBitmap = new BitmapImage(new Uri("pack://application:,,,/Images/All_Sprites/001.png", UriKind.Absolute));
img_ding.Source = carBitmap;
I assume that path ending in 001.jpg
should be changing each time; no doubt you can figure that out. Is it the value of i
in the for loop, stringified and left-padded with zeroes? That'd look like this:
Image img_ding = new Image();
var uri = String.Format("pack://application:,,,/Images/All_Sprites/{0:000}.png", i);
// N.B. UriKind.Absolute is redundant, sigh
BitmapImage carBitmap = new BitmapImage(new Uri(uri, UriKind.Absolute ));
img_ding.Source = carBitmap;
Also, @Clemens is going to provide an answer that shows you how to rewrite the whole thing using an ItemsControl
, which will be much nicer than this. I already wrote somebody a bunch of XAML this morning so it's his turn.
Upvotes: 4
Reputation: 30747
You need to define your bitmap inside the loop, not outside. Then each iteration will create a new bitmap with the new path.
so something like:
for (int i = 0; i < imgCount; i++)
{
// padding left will give you 001 and 010 and 151
string img = i.ToString().PadLeft(3, '0');
BitmapImage carBitmap = new BitmapImage(new Uri("pack://application:,,,/Images/All_Sprites/" + img+".png", UriKind.Absolute));
// the rest of your code
}
Upvotes: 0