#c# #wpf #image #canvas
#c# #wpf #изображение #холст
Вопрос:
поскольку я довольно новичок в C # и WPF, я просто не могу понять, как это сделать. У меня есть форма, в которой должно отображаться 151 изображение (все спрайты pokemon поколения 1) в форме. То, как я это сделал сейчас, заключается в том, что он показывает одно и то же изображение 151 раз вместо всех изображений только один раз. Код, который я написал для этого, выглядит следующим образом:
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 ;
}
}
Как вы можете видеть, в моем коде, вероятно, есть много возможностей для улучшения. Однако мой вопрос: как я могу сделать так, чтобы одно и то же изображение отображалось не 151 раз, а все изображения (sprite001.png, sprite002.png, sprite003.png и т.д.)?
Комментарии:
1. Вы вызываете
img_ding.Source = carBitmap;
151 раз за цикл. Итак, чего же вы ожидаете? Кроме того, вы должны использовать ItemsControl вместо программного добавления элементов управления изображениями на холст.2. Вздох. Теперь у вас есть три ответа, говорящих вам то же самое, все они по-прежнему имеют избыточность
UriKind.Absolute
, но ни один из них не показывает, как использовать ItemsControl . Я напишу один позже, если вам интересно. Ваш исходный код сократится до одной строки.3. Большое спасибо за предложение. Сейчас я нашел решение и, вероятно, попробую другие предложения, а также для учебных целей. Кроме того, я исправил img_ding. Источник = carBitmap; теперь строка. Спасибо за комментарий!
Ответ №1:
Вместо того, чтобы программно добавлять элементы управления изображениями на холст, напишите этот 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>
Возможно, добавьте некоторые Margin
в элемент управления изображением в DataTemplate.
В коде добавьте одну строку в конструктор вашего MainWindow:
using System.Linq;
...
public MainWindow()
{
InitializeComponent();
images.ItemsSource = Enumerable
.Range(1, 151)
.Select(i => string.Format("pack://application:,,,/Images/{0:000}.png", i));
}
Теперь вы можете захотеть создать правильную модель представления, в которой у вас будет свойство типа коллекции для ваших изображений, например
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)));
}
Затем вы должны назначить DataContext окна экземпляру модели представления и привязать к свойству коллекции следующим образом:
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
XAML
<ItemsControl ItemsSource="{Binding Images}">
...
</ItemsControl>
Комментарии:
1. Большое спасибо за комментарии! Я все это сделал, используя ответ @darren, но я также попробую это в учебных целях!
2. Если вы собираетесь продолжить работу с WPF, не будет способа обойти XAML, шаблоны данных и привязку данных. Чем раньше вы начнете делать это правильно, тем лучше.
Ответ №2:
Вы создаете carBitmap
ровно один раз, вне цикла, и используете его каждый раз. Вместо этого создайте новое для каждого изображения.
Image img_ding = new Image();
BitmapImage carBitmap = new BitmapImage(new Uri("pack://application:,,,/Images/All_Sprites/001.png", UriKind.Absolute));
img_ding.Source = carBitmap;
Я предполагаю, что путь, заканчивающийся на 001.jpg
, должен меняться каждый раз; без сомнения, вы можете это понять. Является ли это значением i
в цикле for, упорядоченным и дополненным нулями слева? Это будет выглядеть так:
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;
Кроме того, @Clemens предоставит ответ, который покажет вам, как переписать все это с помощью an ItemsControl
, что будет намного приятнее, чем это. Я уже написал кому-то кучу XAML этим утром, так что теперь его очередь.
Комментарии:
1. oooo. разве вы раньше не видели такой способ форматирования с
{0:000}
помощью -, который делает то же самое, что и padleft?2. @Darren Да, конечно, будет.
3. Эй, это не куча XAML, всего 12 строк 🙂
Ответ №3:
Вам нужно определить свое растровое изображение внутри цикла, а не снаружи. Затем каждая итерация будет создавать новое растровое изображение с новым путем.
итак, что-то вроде:
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
}
Комментарии:
1. Большое спасибо! Это так просто, и он делает именно то, что я хочу, чтобы он делал 🙂