I'm using Visual Studio 2013 WPF and the MVVM Pattern.
I have a Modular Solution, in 1 Project Solution I have many Projects.
Common.Library (Class Library)
This is basically my Library that will contain all the basic stuff e.g the class ViewModelBase.cs Implements the INotifyPropertyChanged. I also have Images folder that contains Images (jpg, png etc.) and another class called BinaryImageConverter.cs to Convert binary images to BitmapImages
Customer (WPF Project)
In here I have a user Control that has a Image control in it. I got my Model/View/ViewModels
CustomerModel : ViewModelBase
private BitmapImage _ProfilePicture;
private BitmapImage ProfilePicture
{
get { return this._ProfilePicture; }
set
{
if (this._ProfilePicture == value)
return;
this._ProfilePicture = value;
OnPropertyChanged("ProfilePicture");
}
}
BinaryImageConverter.cs
public BitmapImage BinaryPictureConverter(byte[] Picture)
{
BitmapImage Image;
if (Picture == null)
return null;
Image = new BitmapImage();
using (MemoryStream imageStream = new MemoryStream())
{
imageStream.Write(Picture, 0, Picture.Length);
imageStream.Seek(0, SeekOrigin.Begin);
Image.BeginInit();
Image.CacheOption = BitmapCacheOption.OnLoad;
Image.StreamSource = imageStream;
Image.EndInit();
Image.Freeze();
}
return Image;
}
CustomerView.xaml
<UserControl.Resources>
<ResourceDictionary>
<BitmapImage x:Key="DefaultCustomerPicture" UriSource="/Common.Library;component/Images/DefaultCustomerPicture.jpg" />
</ResourceDictionary>
</UserControl.Resources>
<Image Name="ImgProfile" Width="150" HorizontalAlignment="Left" DockPanel.Dock="Left" Source="{Binding Path=CustomerProfile.ProfilePicture, TargetNullValue={StaticResource DefaultCustomerPicture}}" Stretch="Fill" />
I have a varbinary field to store my Images in the DB.
So I load my Data in my CustomerViewModel. Everything shows excepts my Image on my UserControl.
I have the FirstName and LastName displayed which is perfect but the Image doesn't appear.
EDIT :
Forgot to mention that my User Control is loaded in a ListBox and the ItemSource is binded to my CustomerProfile which is a ObservableCollection of the CustomerModel
<ListBox Name="listCustomers" Background="Transparent" BorderThickness="0" Margin="5,10,0,0" ItemsSource="{Binding Path=CustomerProfile}">
<ListBox.ItemTemplate>
<DataTemplate>
<vw:CustomerView />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
WPF data binding works with public properties only:
public BitmapImage ProfilePicture
{
get { ... }
set { ... }
}
Related
I am working with XamlCropControl library here. I can't binding image from StorageFile to crop-control.
As for XamlCropControl, they do like that:
<xamlcrop:CropControl x:Name="Crop" ImageSource="ms-appx:///Assets/wrench.jpg" DesiredAspectRatio="1.0" />
But in my case, I need to bind an image that was picked from gallery then pass it to crop-control. I do like bellow, however it did not work at all.
public async void ImageReceiver(StorageFile image)
{
BitmapImage bitmapImage = new BitmapImage();
FileRandomAccessStream stream = (FileRandomAccessStream)await image.OpenAsync(FileAccessMode.Read);
bitmapImage.SetSource(stream);
ImgParam = bitmapImage;
}
private BitmapImage imgParam;
public WriteableBitmap ImgParam
{
get { return imgParam; }
set
{
imgParam = value;
RaisePropertyChanged("ImgParam");
}
}
And in xaml file:
<xamlcrop:CropControl x:Name="CropControl"
ImageSource="{Binding ImgParam, Mode=TwoWay}"
DesiredAspectRatio="1.0"
Background="Black"
Width="100"
Height="100"/>
The following code can add images from a database to a listview, however I would like to bind the image property to the pictures in XAML using Image Source rather than use listview1.Items.Add. Can this code be easily modified to do this or do I have to go about this another way. Hopefully this isn't a stupid question to ask and I would appreciate any help.
public async void showImage()
{
var query = GetAll();
foreach (var stuff in query)
{
string FileName;
FileName = stuff.RecipeImage;
var file = await
Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync(FileName);
var stream = await file.OpenReadAsync();
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
Image ctrlImage = new Image();
ctrlImage.Source = bitmapImage;
ctrlImage.Height = 50;
ctrlImage.Width = 50;
ctrlImage.Stretch = Stretch.UniformToFill;
listView1.Items.Add(ctrlImage);
}
}
I need to add the image to the item source that is already used for my database which contains:
public class AddRecipe
{
[PrimaryKey,AutoIncrement]
public int ID { get; set; }
public string RecipeName { get; set; }
public string RecipeImage { get; set; }
}
<ListView x:Name="listView" HorizontalAlignment="Left" Height="493" Margin="725,60,0,0" VerticalAlignment="Top" Width="528" IsItemClickEnabled="True" SelectionMode="None" ItemClick="listView_SelectionChanged" FontSize="26.667">
<ListView.ItemTemplate>
<DataTemplate >
<StackPanel Orientation="Vertical" Margin="4">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding RecipeName}" Foreground="Black"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding MealType}" Foreground="Black"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
We can use ListView.ItemTemplate to set the DataTemplate used to display each item and put all the images into a ObservableCollection<BitmapImage> as ListView's ItemsSource. Then in DataTemplate, we can use Bind to set the Image.Source. Following is a simple sample:
In XAML, set DataTemplate with {x:Bind} to show image.
<ListView ItemsSource="{x:Bind ImgList}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="BitmapImage">
<Image Width="50"
Height="50"
Source="{x:Bind }"
Stretch="UniformToFill" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ImgList is defined in code-behind, it's defined as ObservableCollection<BitmapImage>, so the DataType of DataTemplate is BitmapImage and as I just bind the whole BitmapImage object to Image.Source so here just use Source="{x:Bind }".
The code-behind may like following:
public sealed partial class MainPage : Page
{
public ObservableCollection<BitmapImage> ImgList = new ObservableCollection<BitmapImage>();
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
showImage();
}
public async void showImage()
{
var query = GetAll();
foreach (var stuff in query)
{
string FileName = stuff.RecipeImage;
var file = await Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync(FileName);
var stream = await file.OpenReadAsync();
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
ImgList.Add(bitmapImage);
}
}
}
Besides, I noticed that you are getting images form Pictures Library. If these images are stored by your app earlier, then storing them in app data would be better as this makes the binding easier and in Pictures Library, these images could be easily deleted by users.
To store images in app data, we can using ApplicationData.Current.LocalFolder to retrieve app's local data folder. For example, copy selected image into local data folder:
//This method copies selected image into local data folder and returns new file's name.
public async Task<string> CopySelectedImage()
{
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Clear();
openPicker.FileTypeFilter.Add(".bmp");
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");
var file = await openPicker.PickSingleFileAsync();
if (file != null)
{
var localFolder = ApplicationData.Current.LocalFolder;
var newCopy = await file.CopyAsync(localFolder, file.Name, NameCollisionOption.GenerateUniqueName);
return newCopy.Name;
}
else
{
return null;
}
}
Then we can using code like following to retrieve the image and create the BitmapImage:
var path = await CopySelectedImage();
var bitmapImage = new BitmapImage(new Uri($"ms-appdata:///local/{path}"));
Update:
I suppose you have had RecipeImage in your item source, then you can add a Image control into your DataTemplate and bind RecipeImage to it's Source with a ImageConverter like following:
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="4" Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Black" Text="{Binding RecipeName}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Black" Text="{Binding MealType}" />
</StackPanel>
<Image Width="50"
Height="50"
Source="{Binding RecipeImage,
Converter={StaticResource ImageConverter}}"
Stretch="UniformToFill" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
ImageConverter is used to convert string to BitmapImage as your RecipeImage is defined as string but Image.Source need a BitmapImage. Before using it in Binding, we need set it as a StaticResource firstly:
<Page.Resources>
<local:ImageConverter x:Key="ImageConverter" />
</Page.Resources>
The code of ImageConverter may like:
public class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
string FileName = value as string;
var file = Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync(FileName).AsTask().Result;
var stream = file.OpenReadAsync().AsTask().Result;
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
return bitmapImage;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Simple
xaml
<ListView Name="listView1">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Image Source="{Binding}" Height="50" Width="50" Stretch="UniformToFill" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
и в коде добавляем List<BitmapImage>
List<BitmapImage> data_list = new List<BitmapImage>();
foreach (var stuff in query)
{
string FileName;
FileName = stuff.RecipeImage;
var file = await
Windows.Storage.KnownFolders.PicturesLibrary.GetFileAsync(FileName);
BitmapImage bitmapImage;
using (var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
}
data_list.Add(bitmapImage);
}
listView1.ItemsSource = data_list;
then we just fill in the data into our ListView
So, I made a "tiny" file explorer page inside my music player (Universal App) and I need to place an image informing wheter is is Directory or file. But the code isn't working.
This is converter itself: namespace myApp before its own namespace.
namespace Converters
{
public sealed class AttributesToImageConverter : Windows.UI.Xaml.Data.IValueConverter
{
public object Convert ( object value, Type targetType, object parameter, string language )
{
FileAttributes f = (FileAttributes)value;
Windows.UI.Xaml.Media.Imaging.BitmapImage img = new Windows.UI.Xaml.Media.Imaging.BitmapImage ( );
img.DecodePixelWidth = 50;
if ( f == FileAttributes.Directory )
{
img.UriSource = new Uri ( "ms-appx:/Asstes/folder.png", UriKind.Absolute );
}
else
img.UriSource = new Uri ( "ms-appx:/Asstes/file.png", UriKind.Absolute );
return img;
}
public object ConvertBack ( object value, Type targetType, object parameter, string language )
{
throw new NotImplementedException ( );
}
}
}
This is XAML:
<Page
...
xmlns:converter="using:myApp.Converters" >
<Page.Resources>
<converter:AttributesToImageConverter x:Key="AttributesToImageConverter" />
</Page.Resources>
...
<Grid x:Name="LayoutRoot" DataContext="">
...
<ListView x:Name="ContentRoot" ItemsSource="{Binding List}" Height="500" Margin="10,-10,10,15" Background="Transparent" BorderBrush="Transparent" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="2,2,2,2">
<Image Width="50" Height="50" Margin="5,0,5,0" Source="{Binding Attributes, Converter={StaticResource AttributesToImageConverter}}" />
<TextBlock Text="{Binding Name}" Foreground="White" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
...
</Grid>
Other Bindings to this context work, binding to Name property in the same IStorageItem works perfectly, this one doesn't. Additionally, using ListView causes the app to shutdown few seconds AFTER displaying the loaded data without any debug information or exception but code -2147483645 (0x80000003). I'd appreciate any help.
Is "Attributes" an actual property for each item within ItemsSource "List" or is it a separate property within your view-model?
Create a storage file with the file path you listed and then leverage the following example:
var imageFile = args.Files[0] as StorageFile;
// Ensure the stream is disposed once the image is loaded
using (IRandomAccessStream fileStream = await imageFile.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
// Set the image source to the selected bitmap
var bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
return bitmapImage;
}
I am facing an issue while displaying an image from ApplicationData.Current.LocalFolder.
I am able to save an image and store it in LocalFolder, but displaying it in a Image control or LongListSelector, the image does not show up.
Here is the code:
private async void StoreToFile(string imageFileName)
{
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(imageFileName, CreationCollisionOption.GenerateUniqueName);
using (Stream current = await file.OpenStreamForWriteAsync())
{
await photoStream.CopyToAsync(current);
}
}
Here is the code to bind:
var folder = ApplicationData.Current.LocalFolder;
var images = await folder.GetFilesAsync();
Recent.ItemsSource = images.ToList();
XAML Code:
<phone:PivotItem Name="pivot1" Header="item2" Background="White">
<phone:LongListSelector x:Name="Recent" Margin="0,0,0,72" ItemsSource="{Binding lst}" >
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Path}" Width="60"/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</phone:PivotItem>
I am able to bind the path to a TextBlock and able to see the exact path like:
C:\Data\Users\DefApps\AppData{GUID}\Local\bucket.png
But if I bind to an image source, images are not displaying.
Can anyone see what I'm doing wrong?
You need to use the msappx uri scheme:
new Uri("ms-appx:///myimage.jpg");
As ToniPetrina has said in comment - you can't bind to Path, your property should return BitmapImage. There are two approaches that come to my mind:
provide a special getter of your property that will return BitmapImage (some code below)
provide a Converter when binding to IsolatedStorage image - here is very nice example
The sample code for the first solution can look like this:
In Xaml:
<ListBox Name="myList" Grid.Row="2">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding GetImgSource}" Width="60"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In code behind:
public class Images : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string imgSource = "";
public string SetImgSource // setter - string
{
set
{
imgSource = value;
RaiseProperty("GetImgSource");
}
}
public BitmapImage GetImgSource // getter - BitmapImage
{
get
{
if (String.IsNullOrEmpty(imgSource)) return null;
BitmapImage temp = new BitmapImage();
using (IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication())
using (IsolatedStorageFileStream file = ISF.OpenFile(imgSource, FileMode.Open, FileAccess.Read))
temp.SetSource(file);
return temp;
}
}
public void RaiseProperty(string property = null)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
ObservableCollection<Images> myImg = new ObservableCollection<Images>();
myList.ItemsSource = myImg; // somewhere
I am trying to retrieve the image from resource file and tryin to bind it to the datagrid of my WPF application.
The datagrid is somewhat like this:
<DataGridTemplateColumn Header="Image" Width="45">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Path=Icon}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
And Image is a property of type image of my MVVm class like this:
public Image Icon
{
get { return _licenseImage; }
set { _licenseImage = value;
PropertChanged("Icon");}
}
And in the code behind Im tryin to do something like this to get image from resource file and tryin to bind it to datagrid column.
ResourceManager resourceManager =
new ResourceManager("Resources.Images", Assembly.GetExecutingAssembly());
BitMap bitmap = resourceManager.GetObject("okimage") as BitMap;
Image image = bitmap;
return image;
I can see that image is populated but it is not displaying in the grid.
You should bind to an ImageSource instead of Image.
we use this helper class:
public static class ImageSourceHelper
{
public static ImageSource GetResourceImage(string resourcePath)
{
return GetResourceImage(Assembly.GetCallingAssembly(), resourcePath);
}
public static ImageSource GetResourceImage(Assembly resourceAssembly, string resourcePath)
{
if (string.IsNullOrEmpty(resourcePath)) return null;
var assembly = resourceAssembly.GetName().Name;
const string uriFormat = "pack://application:,,,/{0};component/{1}";
if (!UriParser.IsKnownScheme("pack")) new System.Windows.Application();
var uri = new Uri(string.Format(uriFormat, assembly, resourcePath), UriKind.RelativeOrAbsolute);
return BitmapFrame.Create(uri);
}
public static ImageSource ConvertFromGdiBitmap(Bitmap bitmap)
{
return Common.SystemAbstraction.Media.ImageConverter.ConvertToBitmapSource(bitmap);
}
public static Bitmap ConvertToGdiBitmap(ImageSource imageSource)
{
return Common.SystemAbstraction.Media.ImageConverter.ConvertToBitmap(imageSource as BitmapSource);
}
}
It creates an ImageSource from Bitmap or resource images.
Usage is
img.Source = ImageSourceHelper("Path/To/Your/Image.png");
or
var resourceAssembly = // get resource assembly...
img.Source = ImageSourceHelper(resourceAssembly, "Path/To/Your/Image.png");
if the image is contained in an other assembly than the currently calling assembly.
The path of your image is the path starting at the project file root of your assembly.
Say you have an folder images your path will be "images/somepicture.png".
I think the problem is that you are binding to the wrong property. Try this:
<Image Source="{Binding Path=Icon}" />