I am trying to retrieve multiple images from isolated storage using listbox but i am not sure why it just only retrieve the lastest image from isolated storage.Therefore hope anyone could help me make amends to my code or could provide me with sample code that works which is about the same as mine.Thanks.
My code :
private void LoadFromLocalStorage(string imageFolder, string imageFileName )
{
var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
if (!isoFile.DirectoryExists(imageFolder))
{
isoFile.CreateDirectory(imageFolder);
}
string filePath = Path.Combine(imageFolder, imageFileName);
using (var imageStream = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read))
{
var imageSource = PictureDecoder.DecodeJpeg(imageStream);
BitmapImage bi = new BitmapImage();
ListBoxItem item = new ListBoxItem();
bi.SetSource(imageStream);
item.Content = new Image()
{
Source = bi, MaxHeight = 100, MaxWidth = 100 };
listBox1.Items.Add(item);
}
It would be helpful if you tell what results are you getting.
Do you see only 1 element?
Do you see multiple elements and they are the same?
Do you see multiple elements and only 1 shows a picture and other are empty?
Anyway this is not a proper way to treat listbox. But first things first.
This line doesn't do anything useful:
var imageSource = PictureDecoder.DecodeJpeg(imageStream);
This code should work (it seems), but there may be an error outside the code. How many times this function is called and what parameters are passed - that is what actually matters.
But I would change the code to use Data Binding and proper ItemsSource.
Create class for items
public class MyImage
{
public string FilePath {get; set;}
public ImageSource LoadedSource {get; set;}
}
Create an ObservableCollection<MyImage>() and fill it with your data.
Bind it to ListBox by setting ItemsSource
Design a proper ItemTemplate with Image and Binding:
<Image Source={Binding LoadedSource}/>
This setup will help you debug the issues easily and localize the problem. It is likely that you are calling your original function incorrectly.
Related
I'm trying to display an Image for an object in a table view, I have created a DisplayModel class in order to display the relevant values in the table columns from an observable collection, I have 2 columns containing string values and one integer all of which are displaying fine, I also have an image of the Car I wish to display but it will only display the Image#Hashcode rather than the image itself.
The implementation I currently have is as follows:
The display model class:
private ObjectProperty<Image> image;
private SimpleStringProperty make;
private SimpleStringProperty model;
private SimpleDoubleProperty price;
public DisplayModel(Image image, String make, String model, Double price) {
this.image = new SimpleObjectProperty<>(image);
this.make = new SimpleStringProperty(make);
this.model = new SimpleStringProperty(model);
this.price = new SimpleDoubleProperty(price);
}
public Image getImage() {
return image.get();
}
public void setImage(Image displayImage) {
this.image = new SimpleObjectProperty<>(displayImage);
}
The implementation in the initialise method on the controller for the FXML file:
try {
OutputStream targetFile = new FileOutputStream(s + "\\" + imageUrl);
targetFile.write(fileBytes);
targetFile.close();
File f = new File(s + imageUrl);
image = new Image(f.toURI().toString());
} catch (IOException e) {
e.printStackTrace();
}
Using the ImageView controller and trying to display the same image presents it fine so I'm wondering whether it's do with the ObjectProperty implementation or the TableView control.. I've recently faced a similar and far more common issue of needing to override the toString method to return the actual value rather than the String#HashValue, I wonder whether there is a similar way to resolve this issue.
Any advice would be greatly appreciated, thanks for your time.
This has to do with the updateItem implementation of the TableCell returned by the default cellFactory. This is implemented as follows (ignoring empty cells):
If the item is a Node, display it using setGraphic with the item as parameter. This adds the Node to the scene inside the TableCell.
Otherwise convert the object to text using it's toString method and use setText to display the resulting value as text in the TableCell.
Image is not a subclass of Node; therefore you get the latter behavior.
To change this behavior, you need to use a custom cellFactory that deals with the item type properly:
ItemImage.setCellFactory(col -> new TableCell<Item, Image>() { // assuming model class named Car here; type parameters match the TableColumn
private final ImageView imageView = new ImageView();
{
// set size of ImageView
imageView.setFitHeight(50);
imageView.setFitWidth(80);
imageView.setPreserveRatio(true);
// display ImageView in cell
setGraphic(imageView);
}
#Override
protected void updateItem(Image item, boolean empty) {
super.updateItem(item, empty);
imageView.setImage(item);
}
});
Note that usually you don't keep the graphic for empty cells. I decided to do this in this case to keep the cell size consistent.
I'm trying to implement a Windows Phone 8 App that works with image handling, trying it to port it from a Windows 8 App. But I got stuck quite quickly, at the beginning.
What I want to achieve is to select some pictures from the phone and show them in my app, in a similar way they look in an album. For this, I've tried some MVVM technique, also. But I'm given an error when I'm trying to create a BitmapImage from the file Stream saying I'm out of range...
Here's my model :
public class SelectedPhoto : IDisposable
{
public Stream Data { get; set; }
public string Name { get; set; }
public BitmapImage Image { get; set; }
public SelectedPhoto(string name, Stream data)
{
Name = name;
Data = new MemoryStream();
data.CopyTo(Data);
Image = new BitmapImage();
Image.SetSource(Data); //Here's the Argument Exception.
}
public void Dispose()
{
Data.Dispose();
}
}
So I'm given the exception quite in the constructor... and I use this in code in a PhotoChooserTask like this :
private void PhotoChooserTaskCompleted(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
PhotosViewModel.AddPhoto(new SelectedPhoto(e.OriginalFileName, e.ChosenPhoto));
}
}
The Argument Exception says : Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. But I'm not manipulating the Stream in any way, I just need it as it is to create the BitmapImage from it, as I've looked after some examples.
How can I get the BitmapImage of a selected image file from phone in this case? Or much better, how can I get it directly as a WriteableBitmap? Because later on, I'm planning on doing some pixel manipulation.
Any type of approach is welcome, thank you.
To fix your code, call the Seek method to go back to the beginning of your stream:
public SelectedPhoto(string name, Stream data)
{
Name = name;
Data = new MemoryStream();
data.CopyTo(Data);
Data.Seek(0, SeekOrigin.Begin);
Image = new BitmapImage();
Image.SetSource(Data); //Here's the Argument Exception.
}
That said, why are you duplicating the stream? You could directly use data.
Does Entity Framework incorrectly detect changes to images?
I have a "Person" entity class defined as follows;
public class Person
{
public int Id { get; set; }
public byte[] Photo { get; set; }
}
I have bound the Photo to a PictureBox control on my form using a datasource.
There form also uses a dynamically created bindingNavigator.
I also have written an audit log to populate captured changes
The procedure calls the ObjectContext DetectChanges() and then
var entries = ObjectContext.ObjectStateManager.GetObjectStateEntries()
Which contains an entry showing that the Photo has been modified.
entry.OriginalValues[name] matches entry.CurrentValues[name]
The Column is varbinary(MAX) in SQL Server and the size of the picture files I have loaded are under 1Mb
If I set all of the columns to null the error no longer occurs
The code I use to get the file is
private void LoadPhotoButton_Click(object sender, EventArgs e)
{
using (var dlg = new OpenFileDialog())
{
dlg.Filter = "JPEG files |*.jpg";
if (dlg.ShowDialog() == DialogResult.OK)
{
PhotoPictureBox.Image = Image.FromFile(dlg.FileName);
}
}
}
I note here that hex zero can be inserted as padding characters when these fields are involved in string conversion.... could the binding be doing that somehow?
If I delete the picturebox from the form, or even bind the control as a text box instead of a picturebox then the behaviour is correct ( not that a picture bound to a text box is any use )
I am able to work around the problem by not binding directly to the picture box.
Instead I just load it on the BindingSource_CurrentChanged event using
private void BindingSource_CurrentChanged(object sender, EventArgs e)
{
var obj = (Person) BindingSource.Current;
this.PictureBox.Image = byteArrayToImage( obj.Photo);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
I am using my work around - documented at the end of the question as a make do answer.
At first of all, MvvmCross is just great. Working with them is really enjoyable.
I have a small problem with secondary tiles in WP7. I have a classic Master-Detail scenario and I want to do secondary tile for Detail (View / ViewModel).
So how can I create a secondary tile from ViewMode?
public IMvxCommand DetailPinCommand
{
get
{
return new MvxRelayCommand<Detail>((d) =>
{
StandardTileData NewTileData = new StandardTileData
{
Title = d.Name
...
...
};
ShellTile.Create(new Uri("/Views/DetailView.xaml?DetailId=" + d.ID, UriKind.Relative), NewTileData);
});
}
}
This is just wrong in viewmodel, and of course it does not work...
Can you help me please?
Mvx includes one example service that allows some simple live tiles/bookmarks to be added - MvxWindowsPhoneLiveTileBookmarkLibrarian.cs
This is currently only implemented for WP7 - but Android and WinRT bookmarks might also be possible using the same template in the future.
If you want to use the librarian service, you can try something like:
IMvxBookmarkLibrarian librarian;
if (!this.TryGetService<IMvxBookmarkLibrarian>(out librarian))
{
// not much can be done...
return;
}
var metadata = new BookmarkMetadata()
{
Title = detail.Name,
};
var uniqueName = "DetailBookmark" + detail.UniqueId;
librarian.AddBookmark(
typeof(DetailViewViewModel),
uniqueName,
metadata,
new Dictionary<string, string>()
{
{ "detailId", detail.UniqueId }
});
This will call through to WP7 code which generates the TileData and a Xaml Uri for the tile - to understand how the uri is generated, see the code around GetXamlUriFor in the librarian.
If you want to use this existing sample service "as is", then the fields currently available in the metadata are:
public Uri BackgroundImageUri { get; set; }
public string Title { get; set; }
public Uri BackBackgroundImageUri { get; set; }
public string BackTitle { get; set; }
public string BackContent { get; set; }
public int Count { get; set; }
but these fields are admittedly currently very WP7 specific - e.g. I doubt the image Uri's will be very reusable across different platforms.
At a practical level, when I develop anything which requires a lot of customisation of the live tile - e.g. downloaded Images - then I normally build a new simple BookmarkLibrarian service based on the existing code, and this customised code sits in the WP7 UI code for that project (and is interface injected into the ViewModel)
I find this customised approach makes the bookmark API much simpler, and it allows me to write the WP7-specific logic within the WP7 application project (rather than in the shared core project).
The key to writing a custom bookmark service is to understand how the navigation uri is generated in 1 - see the code near GetXamlUriFor - the uri is created by serializing an MvxShowViewModelRequest and adding a query parameter which indicates the unique name for this bookmark.
When you've added a bookmark in this way, then you can adjust your "normal" start navigation code in the WP7 App.xaml.cs to something like:
RootFrame.Navigating += (innerSender, args) =>
{
if (!_firstNavigation)
return;
_firstNavigation = false;
var applicationStart = this.GetService<IMvxStartNavigation>();
if (args.Uri.ToString().Contains("MainPage.xaml")
|| !applicationStart.ApplicationCanOpenBookmarks)
{
args.Cancel = true;
RootFrame.Dispatcher.BeginInvoke(applicationStart.Start);
}
};
This code allows bookmarks to be opened directly.
If you ever need to run any code (e.g. an agent) to update the tile to make it "live" then you'll have to do this yourself - I'm afraid there aren't any samples available right now... although I have used Mvx in non-UI projects now in both Android and WP7 - so I know it can be done!
Long time lurker, first time poster here.
My question is:
Using C# 2.0, is there a way to associate am image with a class/type such that I don't have to create an instance of the class just to get the image object from that class?
What I am trying to do is scan all the .dlls in my application and construct a list of classes and corresponding attributes. I have this working great, and now I want to somehow associate an image with each class so that I can display a list of classes and have a unique image for each.
I've tried searching SO and the internet for an answer, but can't find anything definite. Any help would be greatly appreciated.
Thanks,
Kyle
You could create an ImageAttribute.
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
class ImageAttribute : Attribute
{
private string ImagePath { get; set; }
public ImageAttribute(string imagePath)
{
ImagePath = imagePath;
}
public Bitmap Image
{
get { return new Bitmap(ImagePath); }
}
}
Or database id, just some way to identify an image.
Figured out how to do it using ideas here and there.
Mark the image as an EmbeddedResource.
Create an attribute for specifying the image name.
Once the image name attribute is read, use the following to locate the image resource inside the assembly where the class was declared:
string[] all = info.Type.Assembly.GetManifestResourceNames();
foreach (string resourceStr in all)
{
if (!String.IsNullOrEmpty(resourceStr) && resourceStr.EndsWith(String.Format(".{0}", iconName), true, CultureInfo.CurrentCulture))
{
Stream file = info.Type.Assembly.GetManifestResourceStream(resourceStr);
if (file != null)
{
info.Icon = Image.FromStream(file);
}
}
}