Dynamically Added Image to WrapPanel in WPF - wpf

Added Image Controls to WPF WrapPanel from a list of images defined in xml.
Everything seems to be in place. I even inspected in debug but nothing is visual.
Is there a step I am missing?
_printImages.ReadXml(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Images.xml"));
if (_printImages.Tables.Contains("image") && _printImages.Tables["image"].Rows.Count > 0)
{
foreach (DataRow row in _printImages.Tables["image"].Rows)
{
// build info object
ImageInfo imgInfo = new ImageInfo();
imgInfo.Source = row["Source"].ToString();
imgInfo.Custom = bool.Parse(row["Custom"].ToString());
imgInfo.Font = row["Font"].ToString();
imgInfo.FontSize = int.Parse(row["FontSize"].ToString());
imgInfo.CharacterLimit = int.Parse(row["Characterlimit"].ToString());
imgInfo.CustomType = row["Customtype"].ToString();
_images.Add(imgInfo);
//create control
Image imgControl = new Image();
BitmapImage imgFile = new BitmapImage();
try
{
imgFile.BeginInit();
imgFile.StreamSource = new FileStream(imgInfo.Source, FileMode.Open);
imgControl.Source = imgFile;
imgControl.Tag = _images.Count - 1;
imgControl.Height = Properties.Settings.Default.ImageHeight;
imgControl.Width = Properties.Settings.Default.ImageWidth;
imgControl.MouseDown += new MouseButtonEventHandler(image_MouseDown);
imgControl.Visibility = System.Windows.Visibility.Visible;
imageSelectionPanel.Children.Add(imgControl);
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message.ToString(), "Unable to create image");
}
}
}

Your code is missing an EndInit call after setting the StreamSource property of the BitmapImage.
Moreover, the stream should be closed after loading the bitmap, which is usually done by a using block and which also requires to set BitmapCacheOption.OnLoad:
using (var stream = new FileStream(imgInfo.Source, FileMode.Open))
{
imgFile.BeginInit();
imgFile.StreamSource = stream;
imgFile.CacheOption = BitmapCacheOption.OnLoad;
imgFile.EndInit();
}
Alternatively, the BitmapImages could also be loaded directly from the image file paths without using a FileStream:
var imgFile = new BitmapImage(new Uri(imgInfo.Source, UriKind.RelativeOrAbsolute));
You might also create a view model with a collection of ImageInfo objects and bind an ItemsControl to this collection. The ItemsControl would have the WrapPanel as its ItemsPanel, and an ItemTemplate with the Image control:
<ItemsControl ItemsSource="{Binding ImageInfos}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Source}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
See the Data Templating Overview article on MSDN for details.

Related

how to select an image in a list of image in wrappannel wpf

I add images from the filedialog in my programm. i want to kow how i can give them attribute like select_event on click for example to remove one.
Thanks in advance
XAML Code .
<Grid DockPanel.Dock="Top" Margin="5,5,5,5" Background="#FFA59A9A">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<WrapPanel Name="Picture_Holder" HorizontalAlignment="Center" Orientation="Horizontal"/>
</ScrollViewer>
</Grid>
C# code
OpenFileDialog OpenFile = new OpenFileDialog();
OpenFile.Multiselect = true;
OpenFile.Title = "Select Picture(s)";
OpenFile.Filter = "ALL supported Graphics| *.jpeg; *.jpg;*.png;";
if (OpenFile.ShowDialog() == true)
{
foreach(String file in OpenFile.FileNames)
{
Add_Image(file);
}
}
private void Add_Image(string file)
{
Console.WriteLine("Une image"+file);
Image new_img = new Image();
new_img.Source = new BitmapImage(new Uri(file));
Thickness img_thickness = new Thickness();
img_thickness.Bottom = 2;
img_thickness.Left = 2;
img_thickness.Right = 2;
img_thickness.Top = 2;
new_img.Margin = img_thickness;
new_img.MaxWidth = new_img.MaxHeight = 105;
Picture_Holder.Children.Add(new_img);
}
You should use a ListBox like shown below, because it has built-in support for item selection. The WrapPanel would go into the ItemsPanel property of the ListBox.
<ListBox x:Name="imageListBox" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" MaxWidth="105" MaxHeight="105" Margin="2"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Then assign a collection of file path strings to its ItemsSource property:
imageListBox.ItemsSource = OpenFile.FileNames;
You can now get the file path of the selected image by the SelectedItem property of the ListBox.
In order to use BitmapImage items instead of strings - and thus get a BitmapImage as SelectedItem - write:
imageListBox.ItemsSource = OpenFile.FileNames
.Select(path => new BitmapImage(new Uri(path)));
The next step would be to have a view model with a property that holds the image collection:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<ImageSource> Images { get; }
= new ObservableCollection<ImageSource>();
private ImageSource selectedImage;
public ImageSource SelectedImage
{
get { return selectedImage; }
set
{
selectedImage = value;
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(SelectedImage)));
}
}
}
You would assign an instance of the view model to the DataContext property of the MainWindow
DataContext = new ViewModel();
and bind to its properties in XAML:
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Images}"
SelectedItem="{Binding SelectedImage}">
...
</ListBox>
To populate the Images collection in the view model:
var vm = (ViewModel)DataContext;
vm.Images.Clear();
foreach (var path in OpenFile.FileNames)
{
vm.Images.Add(new BitmapImage(new Uri(path)));
}
Remove the selected one by e.g.
vm.Images.Remove(vm.SelectedImage);
which could be executed in an ICommand in the view model.

when i run the code it throws invalid parameter exception how do i fix it?

so i decided to go on a different direction,which was saving the picture name on the database and copying the image in a folder inside my application.
while (reader.Read())
{
BitmapImage bitImg = new BitmapImage();
string fileName =
System.IO.Path.GetFileName(reader.GetString(12));
System.Windows.Controls.Image img = new
System.Windows.Controls.Image();
var impath="pack://application:,,,/TravelBuddyApp;component/images/" + fileName;
bitImg.UriSource = new Uri(impath,
UriKind.RelativeOrAbsolute);
img.Width = 100;
img.Height = 100;
img.Source = bitImg;
StackPanel sp = new StackPanel();
sp.Orientation = Orientation.Vertical;
sp.Children.Add(img);
listviewer.Items.Add(sp);
System.Drawing.Image is WinForms. Do not use it a WPF application.
Use classes derived from System.Window.Media.ImageSource, e.g. BitmapImage:
var bmp = new BitmapImage();
using (var memStm = new MemoryStream(imageBytes))
{
bmp.BeginInit();
bmp.StreamSource = memStm;
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.EndInit();
}
listviewer.Items.Add(bmp);
In case listviewer is a ListBox or ListView, there should be an Image element in the ItemTemplate:
<ListBox x:Name="listviewer">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Programmatically add Panorama Items

I am working on windows Phone 7.5 App and I want to display a list of images programmatically in panorama control.I have the xaml
<!--Panorama item three-->
<controls:PanoramaItem x:Name="DiaPanorama" Header="History" FontSize="20">
and the code part is -
PanoramaItem p = new PanoramaItem();
Image i = new Image();
i.Source = new BitmapImage(new Uri("/web.png", UriKind.Relative));
p.Margin = new Thickness(0, -10, 0, -2);
p.Content = i;
DiaPanorama.Items.Add(p);
but it's showing an error that Microsoft.Phone.Control.PanoramaItem does not contain defination for Items.
How can i solve this problem?Please help.
Is there any other approach for adding images programmatically in panorama?
According to your sample, you're trying to add a new PanoramaItem to an existing PanoramaItem. That won't work - you'd need to add the new PanoramaItem to the parent controls:Panorama object.
When adding multiple items to a PanoramaItem or PivotItem, you must add a containing element first such as a Grid, StackPanel or Canvas
In XAML
<controls:Panorama x:Name="Panorama" Title="Panorama Control">
<controls:PanoramaItem x:Name="Item1" Header="Item 1">
<StackPanel>
<TextBlock Text="Hello World" />
<Image Source="Background.png" />
</StackPanel>
</controls:PanoramaItem>
</controls:Panorama>
In C#
var item = new PanoramaItem();
var panel = new StackPanel();
var text = new TextBlock();
text.Text = "HelloWorld";
panel.Children.Add(text);
var image = new Image();
image.Source = new BitmapImage(new Uri("Background.png", UriKind.Relative));
panel.Children.Add(image);
item.Content = panel;
Panorama.Items.Add(item); // Add to existing panorama control

Binding image source through property in wpf

I am trying to display an icon using an image source(.jpg). I create a Icon property in view model and try to assign it the path of the image but I do not see any image in the view. I tried converting the path to Bitmap image but doesn't work. Is there anything I am missing here?
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}"/>
<Image Source="{Binding Path=Icon}"></Image>
</StackPanel>
BitmapImage img = new BitmapImage();
img.BeginInit();
img.CacheOption = BitmapCacheOption.OnLoad;
img.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
img.UriSource = new Uri("C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg", UriKind.Absolute);
img.EndInit();
Icon = img;
I ran into this myself once and, though maybe not the best solution, the following worked for me.
1. Add the images to your project, for example:
Create a folder images/icons to your project and add the images there.
Set build action of images to Content (copy if newer)
2. Create an ImageSource property:
public ImageSource YourImage
{
get { return _yourImage; }
set
{
_yourImage = value;
NotifyOfPropertyChange(() => YourImage);
}
}
(Note: I use caliburn micro to assist in binding)
3. Update the the ImageSource like this:
if(!string.IsNullOrEmpty("TheImageYouWantToShow"))
{
var yourImage = new BitmapImage(new Uri(String.Format("Images/Icons/{0}.jpg", TheImageYouWantToShow), UriKind.Relative));
yourImage.Freeze(); // -> to prevent error: "Must create DependencySource on same Thread as the DependencyObject"
YourImage = yourImage;
}
else
{
YourImage = null;
}
4. Bind source attribute to YourImage property:
(you already did this)

Listbox carousel - is it possible?

I'm not using a listbox and data binding at the moment, but is it possible to have a listbox work like a carousel and if so, how.
This is what I'm using at the moment, which only works for adding images, not through binding in a listbox... can it still be modified to position each binded canvas+image in the suggested answer?
// add images to the stage
public void addImages()
{
var itemCollection = GalleryModel.DocItemCollection;
foreach (var item in itemCollection)
{
var url = item.ImageUrl;
var image = new Image
{
Source = new BitmapImage(new Uri(url, UriKind.RelativeOrAbsolute))
};
image.Width = 90;
image.Height = 60;
// add the image
LayoutRoot.Children.Add(image);
// Add template here?
// reposition the image
posImage(image, itemCollection.IndexOf(item));
_images.Add(image);
var containingWidth = ActualWidth;
var numberofItemsShown = containingWidth/100;
if (itemCollection.IndexOf(item) < Math.Ceiling(numberofItemsShown)-1)
moveIndex(1);
}
}
// move the index
private void moveIndex(int value)
{
_target += value;
_target = Math.Max(0, _target);
_target = Math.Min(_images.Count - 1, _target);
}
// reposition the image
private void posImage(Image image , int index){
double diffFactor = index - _current;
double left = _xCenter - ((IMAGE_WIDTH + OFFSET_FACTOR) * diffFactor);
double top = _yCenter;
image.SetValue(Canvas.LeftProperty, left);
image.SetValue(Canvas.TopProperty, top);
}
You'd typically use a ListBox for scenarios like this.
The XAML for it would look something like this:
<ListBox x:Name="ImageGalleryListBox">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<tkt:WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding MyImageItemUri}" Margin="8" Width="100" Height="100" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can of course template it further to make things look the way you want.
In the code-behind here or in your view model, you'd create class that has an MyImageItemUri property and add instances of it to an ObservableCollection<T>. You can then bind or set the collection to the ItemsSource of the ImageGalleryListBox. You'd create more images dynamically by simply adding more of your image items to the observable collection.

Resources