I have a WPF application in which I use several images. Most of the images are set in the XAML-code as they will not change anymore. The Build Action of all my image-files are set to "Resource" and the Copy to Output Directory is set to "Do Not Copy". They are shown as expected, here's an example of how they are set:
<ribbon:RibbonApplicationMenu SmallImageSource="/Voetbal;component/Images/Ball_16.png">
//or
<ribbon:RibbonButton LargeImageSource="/Voetbal;component/Images/Calendar_32.png" />
//or
<Image Source="/Voetbal;component/Images/remove.png" Width="16" Height="16" />
But I also have images that have to be set throuch C#. In a UserControl I have a ListView which contains a certain column with following markup:
<GridViewColumn Header="" Width="32">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Icon}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
The ItemsSource for the ListView is a Generic List that contains instances of items that will poulate the ListView. These items have two string-fields and an ImageSource (named 'Icon'). I set the Icon-property like this:
var icon = new BitmapImage(new Uri("/Images/Gold_16.png", UriKind.RelativeOrAbsolute));
myViewModel.Items[0].Icon = icon;
But the problem is that I don't see an image in the ListView. I have also tried following pieces of code. I have used these pieces from answers to similar questions here on SO and on other forums. It's not that I've been lazy or haven't tried anything but I can't figure out how to fix this...
var icon = new BitmapImage(new Uri("/Voetbal;component/Images/Gold_16.png", UriKind.RelativeOrAbsolute));
//or
var icon = new BitmapImage();
icon.BeginInit();
icon.UriSource = new Uri("pack://application:,,,/Voetbal;component/Images/Gold_16.png");
icon.EndInit();
//or
var icon = new BitmapImage();
icon.BeginInit();
icon.UriSource = new Uri("pack://application:,,,/Images/Gold_16.png");
icon.EndInit();
PS: I know the binding of my ViewModel works because the two string-properties are correctly shown in other columns in the ListView.
Does anyone know how I can set the ImageSource and bind it correctly to the ListView?
Thanks in advance!
myViewModel.Items[0].Icon = "Images/Gold_16.png";
Please try the above code. Make the Icon property to string
Related
I have a DataGrid with several bindings for each column. One column is for an image. I already found, that the following way works for binding images in wpf DataGrid.
<DataGridTemplateColumn Header="" Width="SizeToCells" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Width="16" Height="16" Source="{Binding imagePathStatus, IsAsync=True}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
public class DataGridObject
{
public String imagePathStatus { get; set; }
...
}
This is a status and there are 3 types. The same type means the same picture. I had a lot of problems referring to performance of the UI. Especially when my background task invokes the UI after setting the status of one column. But also initializing the GridView (without any other thread besides the UI) takes a long time. Deactivating the image column solves the problem.
I'm searching now for hours and have tried a lot of things.
I've already put the images into resources and uses them via
this.imagePathIcon = "pack://application:,,,/Etlxxx;component/GraphicUserInterface/Images/image.jpg";
I declare the binding to async, so at least the UI will not freeze.
To my mind, the problem is that every row loads the image, even if they uses the same picture. Probably because I just bound the path. According to my knowledge there is no way of binding directly an image.
Everything works fine. But I can see that every Image is loaded separately. I'm really confused.
The pictures are really small (16x16), but still slows down the whole application.
Is there a way to bind the same image to multiple rows in a DataGrid. Ideally, the application has to load an image one time and shows it immediately in every row where it belongs to.
Thanks for your help!
Use a static resource.
<Window.Resources>
<BitmapImage x:Key="MyImageSource" UriSource="./images/error.png" />
</Window.Resources>
<Grid>
<DataGrid Name="dataGrid" >
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Width="16" Height="16" Source="{StaticResource MyImageSource}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
Assuming the image is in "images" directory.
You can of course directly bind to an image, instead of an image path url.
Just declare a property of type ImageSource, e.g.
public class DataGridObject
{
public ImageSource StatusImage { get; set; }
...
}
and bind to it like this:
<Image Source="{Binding StatusImage}"/>
Now you can assign a BitmapImage (or some other ImageSource-derived object), e.g. directly like this:
item.StatusImage = new BitmapImage(new Uri(
"pack://application:,,,/Etlxxx;component/GraphicUserInterface/Images/image.jpg"));
or from a previously created BitmapSource:
item.StatusImage = somePreloadedBitmapImage;
or as well from XAML resources:
item.StatusImage = (ImageSource)Resources["imageResourceKey"];
I'm trying to develop my first Windows Store application.
I'm using the Hub Application template.
I want to display an Image from a Url in the first section of my HubPage:
<HubSection ... >
<DataTemplate>
<Grid ... >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
...
</Grid.RowDefinitions>
<Image Name="UserProfileImage" Margin="100, 0, 100, 0" Grid.Row="0" VerticalAlignment="Top">
<Image.Source>
<BitmapImage UriSource="{Binding ImageUrl}"></BitmapImage>
</Image.Source>
</Image>
</Grid>
</DataTemplate>
</HubSection>
And in my HubPage.xaml.cs:
[DefaultValue("http://images6.fanpop.com/image/photos/34200000/more-dumb-images-of-philip-j-fry-futurama-34257101-1440-900.png"")]
public string ImageUrl { get; set; }
But nothing is shown. If I set manually in the xaml file an image url it works fine...
The problem is, that the Binding mechanism does not know where to look for the ImageUrl property.
You can either set the DataSource of the tag or any of it's parents to an instance of the class, where the property is defined.
Or you use more information in each Binding statement. To bind to yourself, just use
UriSource="{Binding RelativeSource={RelativeSource Self}, Path=ImageUrl}"
or
UriSource="{Binding ImageUrl, RelativeSource={RelativeSource Self}}"
see also WPF Bind to itself
Edit:
You also need to have a notification mechanism on your variable you are binding to. Either make it a DependencyProperty or use a PropertyChanged event (either through INotifyPropertyChanged and call PropertyChanged on changes in the setter with the name of the property, or create an event called <name of property>Changed and invoke this event on changes.
Unfortunately it seems that BitmapSource.UriSource cannot be databound (or more specifically, it can only be bound once and further changes ignored). See discussion here.
In your code you're using <DataTemplate> which means the parent control of this will be either <ListView> or something like that.
Your code reflects very few things about your scenario.
I suggest you to bind ImageSource instead of string
Instead working on XAML part, I suggest you to edit your code-behind part.
I'm briefing the sample here. relate this, with your case and do needful.
Example:-
// BlankPage.xaml ----
// eg. I've a listView and i want to display
// image dynamically in DataTemplate
<ListView x:Name="lstView">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Image Source="{Binding bmp}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Now, define a model class to give itemsSource to ListView.
// In BlankPage.xaml.cs file
public class model
{
public ImageSource bmp { get; set; }
}
Now, say for example I'm assigning itemsSource to ListView in Page_Loaded event.
// in BlankPage.xaml.cs file
// declare this BlankPage's Loaded event in BlankPage's Constructor
// and define the event handler like this
void BlankPage2_Loaded(object sender, RoutedEventArgs e)
{
model m1 = new model()
{
bmp = new BitmapImage(new Uri("ms-appx:///Assets/TechVista(300x300).png", UriKind.Absolute))
};
// here "ms-appx:///Assets/TechVista(300x300).png" should be the Full-System-Path where image is located.
// and according to that declare the UriKind as Relative or Absolute or other.
List<model> lstModels = new List<model>();
lstModels.Add(m1);
// you can add as many models as you want here.
// for reference I'm adding only one here.
lstView.ItemsSource = lstModels;
}
It will work for sure.
For more exact answer, elaborate little more here.
Hope that helps..!
i have a image control in wpf like this
<Image x:Name="Img" Source="{Binding IsAsync=True}" />
i set the image by fetching from a url like this
Img.DataContext = ImageUrl;
it shows fine and when i want to clear it i just use
Img.DataContext=null;
for the same control i have a browse button as well to select the image from local path like this
BitmapImage image = new BitmapImage(new Uri(path));
Img.Source=image;
now i want to clear that as well so i do
Img.Source=null;
after that the control wont show the image from url only local images can be opened
Edit: probably i need to set the binding again after making source to null, not sure how to do that
You are abusing bindings horribly. Please stop.
<Image x:Name="Img" Source="{Binding IsAsync=True}" />
Says "Bind to the data context", which isn't all that great. Bind to a property of your view model, something like:
<Image x:Name="Img" Source="{Binding Path=ImageLocation, IsAsync=True}" />
And then only ever change the image using ImageLocation. At the very least, only set it via the DataContext.
Once you set the source to a binding, you should never be changing it via code-behind. Period. Do that, and your problem will "magically" disappear, as you are doing it the right way now.
To clear image control, clear image url.
e.g imgControlName.ImageUrl = "";
i have a little problem with my WPF-Application.
Well, i have a ListView which shows at the first column a image. Each element can or cannot have a image, so from time to time i load a "default" image in this column.
Here is the problem.
When i load the default image, there is no image shown in the listview.
Here is the codepart, which adds the default image:
Uri src = new Uri(#"/myapp;component/Images/Picture.png", UriKind.RelativeOrAbsolute);
BitmapImage small_image_bmp = new BitmapImage();
small_image_bmp.BeginInit();
small_image_bmp.CacheOption = BitmapCacheOption.OnLoad;
small_image_bmp.UriSource = src;
small_image_bmp.EndInit();
small_image_bmp.Freeze();
dto.Bild1_Bitmap = small_image_bmp;
this.liste.Add(dto);
This code is not working.
But this part works very well:
Uri src = new Uri(#"C:\Users\me\Documents\Visual Studio 2010\Projects\myapp\myapp\Images\Picture.png", UriKind.RelativeOrAbsolute);
BitmapImage small_image_bmp = new BitmapImage();
small_image_bmp.BeginInit();
small_image_bmp.CacheOption = BitmapCacheOption.OnLoad;
small_image_bmp.UriSource = src;
small_image_bmp.EndInit();
small_image_bmp.Freeze();
dto.Bild1_Bitmap = small_image_bmp;
this.liste.Add(dto);
As you can see, the part who isnt working has a relative path and the code, who is working, has a absolute path.
But of course i cant use the absolute path...
Here is the XAML of the ListViewColumn:
<GridViewColumn Header="Bild">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="100" Height="100" Source="{Binding Bild1_Bitmap}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
If code you posted for loading an image is in same assembly as of image. You can ignore component path and use like this - Images\Picture.png.
Also make sure image build action is set to Resource.
I am trying to display some images in a ListView and have not been successful. I am using WPF MVVM and the ListView is a holdover from simply displaying suits and rank data. (See my previous post: MVVM in WPF - How to alert ViewModel of changes in Model... or should I? if you are interested!) That is, I could use something other than ListView (if that is the advice) but I would still like to know how to do it with ListView, assuming it's doable. My property I'm binding to in the ViewModel is:
public ObservableCollection<Image> PlayerCardImages{
get{
ObservableCollection<Image> results = new ObservableCollection<Image>();
foreach (CardModel card in PlayerCards)
{
Image img = new Image();
BitmapImage bi3 = new BitmapImage();
bi3.BeginInit();
// TODO: Pick card based on suit/rank. Just get 1 image working now
bi3.UriSource = new Uri("diamond-1.png", UriKind.Relative);
bi3.EndInit();
img.Stretch = Stretch.Fill;
img.Source = bi3;
results.Add(img);
}
return results;
}
}
In my XAML code I'm using:
<Window.Resources>
<DataTemplate x:Key="ImageCell">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding PlayerCardImages}" Width="200" Height="200" Stretch="Fill" ToolTip="Add tooltip"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel Orientation="Vertical">
<Label Content="Player Cards"/>
<ListView Name="lvwTitles" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
SelectionMode="Single" ItemTemplate="{StaticResource ImageCell}" Height="59">
</ListView>
</StackPanel>
This idea was shamelessly stolen from: WPF - bind images horizontally to ListView However, it doesn't even appear to databind as evidenced by my breakpoint in PlayerCardImages not being hit.
I also tried the following XAML with somewhat better luck:
<StackPanel Orientation="Vertical">
<Label Content="Player Cards"/>
<ListView
AlternationCount="2"
DataContext="{StaticResource PlayerCardsGroups }"
ItemsSource="{Binding}"
>
<ListView.GroupStyle>
<StaticResourceExtension
ResourceKey="CardGroupStyle"
/>
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn>
<Image Height="50" Width="40"></Image>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
<Window.Resources>
<CollectionViewSource x:Key="PlayerCardsGroups"
Source="{Binding Path=PlayerCardImages}">
</CollectionViewSource>
<GroupStyle x:Key="CardGroupStyle">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock
x:Name="txt"
Background="{StaticResource Brush_HeaderBackground}"
FontWeight="Bold"
Foreground="White"
Margin="1"
Padding="4,2,0,2"
Text="Cards"
/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
<Style x:Key="CardItemStyle" TargetType="{x:Type ListViewItem}">
<!--
Stretch the content of each cell so that we can
right-align text in the Total Sales column.
-->
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<!--
Bind the IsSelected property of a ListViewItem to the
IsSelected property of a CustomerViewModel object.
-->
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ItemsControl.AlternationIndex" Value="1" />
<Condition Property="IsSelected" Value="False" />
<Condition Property="IsMouseOver" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="#EEEEEEEE" />
</MultiTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
this code definitely goes through databinding - my breakpoint is hit at the beginning of the program and whenever items are added to the collection. But no images is displayed. Rather than torture you with more XAML that does not work, perhaps I could ask someone to point me to some code/examples/docs that show how to bind a list of Images to a ListView (or another control if you really feel that ListView is inappropriate). Notice that my collection is the stuff I'm binding to. I notice that with many examples, they are binding to a subproperty. I.e. they may have a collection of albums and for each album they bind to it's property image (see: Showing items as images in a WPF ListView).
Any ideas or help would be much appreciated.
-Dave
Additional info.
Based on suggestions by Clemens, I now have this code for PlayerCardImages:
public ObservableCollection<ImageSource> PlayerCardImages
{
get
{
var results = new ObservableCollection<ImageSource>();
//if (PlayerCards.Count == 0)
// return results;
//else
//{
// results.Add(new BitmapImage(new Uri(#"Images\\" + "diamond-1.png", UriKind.Relative)));
//}
foreach (var card in PlayerCards)
{
results.Add(new BitmapImage(new Uri(#"Images\\" + GetCardFileName(card), UriKind.Relative)));
}
return results;
}
I used the exact XAML he suggested. It almost works. I say "almost" because I noticed strange behavior whereby sometimes 1 card would show and sometimes not (I never got 2 cards). All the getting cards from files and binding seems to be working and I tracked down what I think is key to the last remaining bug (and it's BIZARRE). If in the debugger, I examine results, and further open up results[0] in the debugger, I get that card displayed! I actually have to open up [0] (you see info about height, width, etc.) for this to work. Furthermore if I open up [1], I get that card displayed instead. Why would opening up the debugger info have any effect? For those of you who might ask, what happens if you open up both cards in the debugger... that doesn't work. I get a operation timed out exception. I will say that perhaps my image files are big. 10Kbytes to 30 Kbytes. Is that the problem? I'm guessing not, and that it's a subtle problem with reading in the images or binding. What is going on? Thanks, Dave
First, you should not use Image controls in your ViewModel. You already have an Image control in the DateTemplate of your view. You want to bind the Source property of this Image conntrol, and the source property of this binding can't be another Image.
Instead your ViewModel would either use ImageSource (or a derived class like BitmapImage) as image type, like this:
public ObservableCollection<ImageSource> PlayerCardImages
{
get
{
var results = new ObservableCollection<ImageSource>();
foreach (var card in PlayerCards)
{
results.Add(new BitmapImage(new Uri(card.ImageUrl)));
}
return results;
}
}
Or simply the image URIs or paths, as there is an automatic conversion from string to ImageSource built into WPF:
public ObservableCollection<string> PlayerCardImages
{
get
{
var results = new ObservableCollection<string>();
foreach (var card in PlayerCards)
{
results.Add(card.ImageUrl);
}
return results;
}
}
You would now bind your Listbox's ItemsSource property to the PlayerCardGames collection, and in the DataTemplate you bind directly to the collection item. The ListView's DataContext has to be set to an instance of the object that defines the PlayerCardGames property.
<ListView ItemsSource="{Binding PlayerCardGames}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
UPDATE: As there seems to be a problem with loading the image files, you may try the following method. It loads images synchronously and you are able to step through with the debugger.
public static ImageSource LoadImage(string fileName)
{
var image = new BitmapImage();
using (var stream = new FileStream(fileName, FileMode.Open))
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
}
return image;
}
You can use this method in your PlayerCardGames property getter like this:
foreach (var card in PlayerCards)
{
results.Add(LoadImage(#"Images\\" + GetCardFileName(card)));
}
I didn't really try to reproduce your problem, but I will if this is not solving it:
In your first xaml block, I think you mixed up the bindings. This would be how I expect it, ItemsSource to the ObservableCollection of Images, Image source to the Image.
<Image Source="{Binding}" ... />
<ListView Name="lvwTitles" ItemsSource="{Binding PlayerCardImages}" ... />
In your second block, you omitted the Source binding altogether:
<Image Source="{Binding}" Height="50" Width="40" />