How to do array for images? - c#

I have 20 images, they are ball1, ball2, ..., ball20.
Supposedly, I inserted the images using
Image x:Name="ball1" Source="/Images/ball1.png" Canvas.Left="150" Canvas.Top="200" in .xaml.
Currently, I tried to insert it in this way
Uri uri = new Uri("/Images/ball1.png", UriKind.Relative);
ImageSource img = new System.Windows.Media.Imaging.BitmapImage(uri);
image.SetValue(Image.SourceProperty, img);
cv.Children.Add(image);
However, I could not use it this way because it does not specify the position that I want to insert it.
I want to avoid doing it through .xaml, how can I do it using array in .cs?

You can declare the Image objects in XAML and then update the Source properties from your code behind or view model if you prefer. For this method, you will need one property per image in your view model or code behind:
public string Image1SourcePath
{
get { return image1SourcePath; }
set { image1SourcePath = value; NotifyPropertyChanged("Image1SourcePath"); }
}
...
public string Image20SourcePath
{
get { return image20SourcePath; }
set { image20SourcePath = value; NotifyPropertyChanged("Image20SourcePath"); }
}
Ensure you implement some form of INotifyPropertyChanged interface
<Image Source="{Binding Image1SourcePath}" Canvas.Left="150" Canvas.Top="200" />
...
<Image Source="{Binding Image20SourcePath}" Canvas.Left="1500" Canvas.Top="200" />
Then in your view model or code behind:
Image1SourcePath = "/YourApplicationName;component/Images/ball1.png";
...
Image20SourcePath = "/YourApplicationName;component/Images/ball20.png";
It's a lot of code, but it allows you to update the Image.Source properties from your code behind and set the positions in XAML.

You can do this by calling the appropriate static methods on the Canvas class that set the attached properties (Canvas.Left & Canvas.Top).
Uri uri = new Uri("/Images/ball1.png", UriKind.Relative);
ImageSource img = new System.Windows.Media.Imaging.BitmapImage(uri);
image.SetValue(Image.SourceProperty, img);
cv.Children.Add(image);
// Position the image on the canvas
Canvas.SetLeft(150);
Canvas.SetTop(200);
If you have a list of images to display, you could do something like:
List<Uri> imageUris = new List<Uri>()
{
new Uri(#"C:\Users\Grant\Pictures\Heron_zoomed.png"),
new Uri(#"C:\Users\Grant\Pictures\bridge.jpg")
};
int left = 20;
int top = 10;
foreach (var uri in imageUris)
{
Image image = new Image { Source = new BitmapImage(uri) };
Canvas.SetLeft(image, left);
Canvas.SetTop(image, top);
MainCanvas.Children.Add(image);
left += 400;
}
The code above assumes you have something like the following in your window xaml and that the file names in the imageUris list exist.
<Grid>
<Canvas x:Name="MainCanvas">
</Canvas>
</Grid>
I have no idea what you are trying to do with these images. If you just want to display them in a grid you could use one of the WPF collection controls to do this without any code.
One way of doing this is Displaying images in grid with WPF
I suspect there are better alternatives but this would be a start.

Related

XAML WPF -Why the background image of button does not change?

I am new to XAML, and I am trying to change the background image of buttons.
So, the original background image is heart.jpg.
I wrote function changeHearts() that suppose to check if the background image is: skull.png ,
So it will change the image of the button to: heart.jpg .
The problem is that when I call the function, it does not change the image of the buttons.
Both of the 2 images property is set to: resource.
*Function in my c# code:
private void changeHearts()
{
Uri resourceUri = new Uri("/Images/skull.png", UriKind.Relative);
StreamResourceInfo streamInfo = Application.GetResourceStream(resourceUri);
BitmapFrame temp = BitmapFrame.Create(streamInfo.Stream);
var brush2 = new ImageBrush();
brush2.ImageSource = temp;
Uri resourceUri1 = new Uri("/Images/heart.jpg", UriKind.Relative);
StreamResourceInfo streamInfo1 = Application.GetResourceStream(resourceUri1);
BitmapFrame temp1 = BitmapFrame.Create(streamInfo1.Stream);
var brush = new ImageBrush();
brush.ImageSource = temp1;
foreach (Button btn in split1.Children)
{
if (btn.Background == brush2)
btn.Background = brush;
}
foreach (Button btn in split2.Children)
{
if (btn.Background == brush2)
btn.Background = brush;
}
}
The problem is that when I call the function, it does not change the image of the buttons. Please help me, any advice will be great.
That is because you compare references of ImageBrush instances with the == operator. The comparison will always fail, because each ImageBrush that you define in XAML and in your code is a distict instance with a unique reference. Consequently, they are never equal.
I wrote function changeHearts() that suppose to check if the background image is: skull.png , So it will change the image of the button to: heart.jpg .
The most simple solution to this is to not compare the image brushes at all. Your buttons either have a Skull or a Hearts image as background. Now, when you call changeHearts() two things can happen:
A button was Skull and will now be changed to Hearts
A button was Hearts and will now be changed to Hearts
In both cases the result will be that the corresponding buttons will be Hearts, so you could just remove the checks and get the same result.
Comparing brushes is hard as the Equals method won't do the trick either. You would have to create custom comparison logic, e.g. find properties on brushes to compare, but I do not recommend it.
An alternative could be to assign the Tag of your buttons with an identifier for what is currently displayed, Hearts or Skull. This could be a custom enum or a simple string, e.g.:
public enum ButtonType
{
Skull,
Hearts
}
Then assign the the initial button type to your buttons in XAML:
<Button x:Name="XLife1" Tag="{x:Static local:ButtonType.Hearts}" Grid.Column="0" Width="80" Height="80">
<Button.Background>
<ImageBrush ImageSource="/images/heart.jpg"/>
</Button.Background>
</Button>
Adpat your methods to check the Tag property of button and change the tag if it matches:
if (btn.Tag.Equals(ButtonType.Hearts))
{
btn.Tag = ButtonType.Skull;
btn.Background = brush;
}

How to bind the Image.Source in MVVM correctly?

I spent some time now trying to work this out but I am still stuck on it. I have a WPF application with a MVVM pattern. In my ViewModel I have three cases where:
X needs Y and Y is available
X needs Y and Y is not available
X doesn't need Y
I am trying to set an image icon on my view based on these conditions (Like a Check Mark, exclamation Mark... whatever).
In ViewModel:
I created my properties. On any GUI change, I set the variables based on the above cases similar to the following:
void MyBigFunctionToSetAllProperties()
{
// other cases
// ..
if (NeedsY && YExists)
{
// properties
StatusIconPath = "#\"/Resources/SessionView/X-With-Green-Check-White.png\"";
ResultIconPath = "#\"/Resources/SessionView/Y-White.png\"";
}
}
In View.Cs: I did literally nothing.
In View.xaml: I bind like this:
<StackPanel>
<Image Source="{Binding StatusIconPath} />
</StackPanel>
I still can't see why it is not working. What is that thing that I am missing? Please and thanks.
It did not work to bind the properties directly with the Xaml as recommended. I tried it this way:
VM: sample property:
public BitmapImage VerificationStatusIcon{ get { return new BitmapImage(new Uri(#VerificationStatusIconPath, UriKind.Relative));}}
View Xaml:
<Image Name="verificationStatusImage" Source="{Binding VerificationStatusIcon}" Margin="5,0" Width="40" Height="40"/>
You have a whole bunch of unnecessary characters in your icon paths:
StatusIconPath = "#\"/Resources/SessionView/X-With-Green-Check-White.png\"";
ResultIconPath = "#\"/Resources/SessionView/Y-White.png\"";
Change them to this:
StatusIconPath = "Resources/SessionView/X-With-Green-Check-White.png";
ResultIconPath = "Resources/SessionView/Y-White.png";
. But no images originally to view and no changes..
Verify that the path to the image is correct. Maybe hard code an image to test the control against it.
One other scenario is that the resources are not being copied over for run-time acquisition. Make sure they are actually available during runtime.
can't see why it is not working
Is the main view's DataContext set to the live VM's instance?
What is that thing that I am missing?
If you are sure that the view's datacontext contains the live VM, then make sure that the property StatusIconPath on the VM reports a property change event.
That is so that the XAML control which is bound to it knows that it changed and correspondingly one needs to make sure that the ViewModel which holds StatusIconPath adheres to INotifyPropertyChanged which will facilitate such an operation in general:
private string _StatusIconPath;
public string StatusIconPath
{
get { return _StatusIconPath; }
set
{
_StatusIconPath = value;
PropertyChanged("StatusIconPath");
}
}
I provide more robust example on my blog entitled:
Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding
It turned out that I have an extra unneeded characters in my ImagePaths as Kyle stated. And then, I needed to set my Image.Source from within my View.cs. At least, this is how it worked for me:
ViewModel Something like this:
if (Whatever)
{
StatusIconPath = "/Resources/SessionView/X-With-Green-Check-White.png";
ResultIconPath = "/Resources/SessionView/Y-White.png";
}
Then in View.cs and on SelectedItemChanged:
private void Grid_SelectedItemChanged(object sender, DevExpress.Xpf.Grid.SelectedItemChangedEventArgs e)
{
string tempStatus = ((SessionViewModel) DataContext).StatusIconPath;
string tempResult = ((SessionViewModel) DataContext).ResultIconPath;
StatusImage.Source = new BitmapImage(new Uri(#tempStatus, UriKind.Relative));
ResultImage.Source = new BitmapImage(new Uri(#tempResult, UriKind.Relative));
}
and in Xaml: just a fallback value(any original/default image we want). Ex:
<Image Name="ResultImage" Source="/EZ3D;component/Resources/SessionView/Retake-White.png"/>

Need directions on how to make a List with different items, to bind it to a ListView

I need to make a ListView where each row will have an image, then a Text, then another image.
Since to make a GridView I had to bind its DataContext to a List with all the images, and they work (almost) the same way, I think I need to make another List with the images and texts
The format is: "Store Logo. Promotion Text. Credit Card Logo" and all this data comes from an API.
I already have all the pictures saved in different folders ("Stores" and "PaymentMethods") and I get the text like
myTextBlock.text = item.promotion;
Now my questions are:
1) Is it possible to make a list with all this data? How? (or where do I have to look for it)
2) Once I have the list, how, by binding it, can I be sure that it will respect the format I mentioned above?
(Something I tried out, instead of having a ListView, was creating everything at runtime:
public async void getPromos()
{
if (Resp.searchResults.Count > 0)
{
var selected = from promo in Resp.searchResults
where (promo.store_id != null || promo.method_id != null)
select new
{
store = promo.store_id,
medio = promo.method_id,
endDay = promo.to,
promocion = promo.desc
};
foreach (var item in selected)
{
Debug.WriteLine(item.store);
await showPromos(item.store, item.medio, item.endDay, item.promocion);
}
}
}
async Task showPromos(string store, string medio, string endDay, string promocion)
{
Debug.WriteLine(store);
Debug.WriteLine("medio" + medio);
StorageFolder folder1 = await KnownFolders.PicturesLibrary.GetFolderAsync("UnicenterMediosFolder");
StorageFolder folder2 = await KnownFolders.PicturesLibrary.GetFolderAsync("UnicenterStores");
if (store != null)
{
StorageFile file = await folder2.GetFileAsync(store + ".png");
ImageProperties properties = await file.Properties.GetImagePropertiesAsync();
if (properties.Width > 0)
{
var bitmap = new WriteableBitmap((int)properties.Width, (int)properties.Height);
bitmap.SetValue(NameProperty, (string)properties.Title);
Debug.WriteLine(bitmap.PixelWidth);
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
bitmap.SetSource(stream);
}
Color customColor = ColorHelper.FromArgb(213, 213, 213, 213);
StackPanel casa = new StackPanel();
casa.Orientation = Orientation.Horizontal;
casa.Background = new SolidColorBrush(customColor);
casa.Height = 70;
Image promoImage = new Image();
promoImage.Source = bitmap;
promoImage.Width = 70;
promoImage.Height = 70;
TextBlock thePromo = new TextBlock();
thePromo.Text = promocion;
thePromo.Foreground = new SolidColorBrush(Colors.Gray);
casa.Children.Add(promoImage);
casa.Children.Add(thePromo);
gridForPromos.Children.Add(casa);
Debug.WriteLine("aaa" + gridForPromos.Children.Count);
}
}
}
and in my xaml:
<ScrollViewer x:Name="myPromoSpace" Grid.Row="2">
<Grid x:Name="gridForPromos"/>
</ScrollViewer>
But doing this, I get each stackpanel on the previous one, instead of having them one under the other)
Can you guys point me in the right direction here, please?
When you add elements to a Grid without setting Grid.Row and having Grid.RowDefinitions, all the childs will be in the same grid cell. You either need to add RowDefinitions and set the row of the child:
gridForPromos.RowDefinitions.Add(new RowDefinition(...))
Grid.SetRow(casa, gridForPromos.RowDefinitions.Count);
or replace your Grid with a StackPanel:
<StackPanel x:Name="gridForPromos" />
But I would prefer to define a DataTemplate for your Items. With this you can define the visual apperance of your items in XAML and simple bind a StackPanel to your items. Here a link that shows you how to do: http://www.wpftutorial.net/datatemplates.html

updating an image in an image control

im trying to update an image in an image control that is bound to a class which implements INotifyPropertyChanged. i've tried most of the methods which relate to refreshing bitmap cache so that the image can refresh but none seems to work for my case. the image contorl is defined in the xaml file as: <Image Source="{Binding Chart}" Margin="0 0 0 0"/>
and in the code behind the class is:
private ImageSource imagechart = null;
public ImageSource Chart
{
get
{
return imagechart;
}
set
{
if (value != imagechart)
{
imagechart = value;
NotifyPropertyChanged("Chart");
}
}
}
after an event i now set the image using the following code:
c.Chart = image;
when i now run my application this will display the image but during the running of the application i update the image but calling this c.Chart = image; displays the initial image. i came to understand that WPF caches the image but all methods claiming to solve this dint work for me. one of the solutions that did not work for me is Problems overwriting (re-saving) image when it was set as image source
Try to change the return Type of your Image property to Uri. The TypeConverter on the Source Property should do the rest. If this doesnt work, verify that the resource has actually changed.
You can read the resource from your assembly using Assembly.GetManifestResourceStreams and resolve the bytes. Than manually save them with File.WriteAllBytes to your output directory an see if it has the expected image.
As far as i know Application Ressources (which are embedded into the assembly) can not be changed during runtime (?). You are referencing the assembly ressource and not an output ressource with your pack uri.
thank you all for your input coz through them i finally figure a way around this. so my xaml still remains bound as <Image Source="{Binding Chart}" Margin="0 0 0 0"/> but in the code behind i changed the class property chart to return a bitmap as shown below:
private BitmapImage image = null;
public BitmapImage Chart
{
get
{
return image;
}
set
{
if (value != image)
{
image = value;
NotifyPropertyChanged("Chart");
}
}
}
this class mind you implements INotifyPropertyChanged . at the point where i set the image i am now using this code:
BitmapImage img = new BitmapImage();
img.BeginInit();
img.CacheOption = BitmapCacheOption.OnLoad;
img.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
//in the following code path is a string where i have defined the path to file
img.UriSource = new Uri(string.Format("file://{0}",path));
img.EndInit();
c.Chart = img;
this works well for me and refreshes the image upon update.

Adding Image to wpf

I want to add an Image dynamically to the wpf application.
What I have tried :
Image img = new Image();
img.Height = 100;
img.Width = 100;
img.Visibility = Visibility.Visible;
Thickness th = new Thickness(100, 100, 0, 0);
img.Margin = th;
string strUri2 = String.Format(#"pack://application:,,,/MyFirstWPF;component/Images/tt.jpg");
img.Source = new BitmapImage(new Uri(strUri2));
I know, the image won't display unless I add it to the Content.
this.Content=img;
but with this the existing controls(shapes) on the app are lost.
Now, my question is how to add the image to the content without losing existing controls from the app.
When you are going to load and show an image dynamically, you still need to think about the layout of your application. I would suggest to add an (initially empty) Image control in XAML (for example in a Grid), and later set the Source property of this control in code.
<Grid>
... other controls ...
<Image Name="img" Grid.Row="..." Grid.Column="..."
Width="100" Height="100" Margin="100,100,0,0"/>
</Grid>
Set Source in code:
var uri = new Uri("pack://application:,,,/MyFirstWPF;component/Images/tt.jpg");
img.Source = new BitmapImage(uri);
by default the window content is a grid so try
(this.Content as Grid).Children.Add(img);

Categories

Resources