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

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;
}

Related

how to cast (or convert) an ImageSource to FileImageSource [duplicate]

I am trying add a background image using the image property in button. The issue I'm facing is that i can't set StreamImageSource as button background. I encountered the error given below if I try to do so.
The Code I use to set Image:
ImageSource iconsource =ImageSource.FromStream(() => new MemoryStream(ImgASBytes));
Button Icon = new Button ();
Icon.Image = iconsource ;
The Error I encounter:
Error CS0266: Cannot implicitly convert type 'Xamarin.Forms.ImageSource' to 'Xamarin.Forms.FileImageSource'. An explicit conversion exists (are you missing a cast?)
ImageSource.FromStream () returns a StreamImageSource (see docs). Button.Image accepts only FileImageSource (see docs).
It means that what you're trying to achieve won't work, no matter how hard you try to cast one into the other.
Button.Image will accept images stored as resources in your platform projects, and loaded either with:
Icon.Image = ImageSource.FromFile ("foobar.png");
or
Icon.Image = "foobar.png";
The accepted answer is true that you can't cast StreamImageSource to FileImageSource, I think that the real question is about how to share images in a PCL and use them on a button, just like one would when creating an Image forms control.
The answer is to have a Grid which contains both a Button and an Image object, where the Image overlaps the Button.
For example, the C# code might look like this:
ImageSource imageSource = ImageSource.FromStream(() => new MemoryStream(imageAsBytes));
Button iconButton = new Button ();
iconButton.VerticalOptions = LayoutOptions.FillAndExpand;
iconButton.HorizontalOptions = LayoutOptions.FillAndExpand;
var image = new Image();
image.Source = imageSource;
// So it doesn't eat up clicks that should go to the button:
image.InputTransparent = true;
// Give it a margin so it doesn't extend to the edge of the grid
image.Margin = new Thickness(10);
var grid = new Grid();
// If we don't set a width request, it may stretch horizontally in a stack
grid.WidthRequest = 48;
// Add the button first, so it is under the image...
grid.Children.Add(iconButton);
// ...then add the image
grid.Children.Add(image);
You may have to play with the sizes and thickness values but this should get you a clickable button with an icon.
As of Xamarin.Forms 3.4.0 you can now use ImageButton. You can use embedded images by using an extension method explained in this MS document
Careful with upper- and lowercase in filenames.
I was wondering, why my button-images were shown properly on the simulator, but not on my iPhone.
On the device the filename must match exactly, the simulator doesn't care about upper- and lowercase in filenames.
I use this and it works
var imageA = new Image();
imageA.Source=(FileImageSource)ImageSource.FromFile(allergeneLocation)};
or
var imageA = new Image()
{
BackgroundColor = Color.Teal,
Source = (FileImageSource)ImageSource.FromFile(allergeneLocation)},
};
Here is what I tried:
Button refreshBut = new Button
{
Image = (FileImageSource)
(ImageSource.FromFile("refreshBut.png"))
};
While it compiles I then get an unhandled null reference exception with the description: Object reference not set to an instance of an object. I am not sure if this will help anyone else try to solve this but I am at the same wall.

c# wpf button with variable as name? same colours in all buttons

Hello I have 2 questions.
This is my code: (kolLos make random number between 0 and 255)
public int numer_prostokata = 1;
private void Glowny_przycisk_Click(object sender, RoutedEventArgs e)
{
// Create a Button
Button blueRectangle = new Button();
blueRectangle.Content = numer_prostokata;
var nazwa_batona = "s_b_" + numer_prostokata;
blueRectangle.Name = nazwa_batona;
MainWindow.Children.Add(blueRectangle);
myColor.Color = Color.FromArgb(kolLos(), kolLos(), kolLos(), kolLos());
blueRectangle.Background = myColor;
numer_prostokata++;
}
It almost work. Buttons are generating on click. They have different Contents, but... always the same color. Colors are changing after each Click, but all buttons have the same (for example all red or all blue)...
What I did wrong?
And second question:
name of Buttons is "s_b_" + number. It is in var "nazwa_batona". But when I use
nazwa_batona.Background = myColor;
it doesn't work... What should I do?
I'm very begining in C#... I googled and searched many hours but didn't find answers...
Oh! There can be many buttons created and they can be in different places...
I'm assuming myColor is some class level SolidColorBrush since it isn't declared in the function. Given that, the following code simply changes the color of that brush, then assigns the brush to the new button instance:
myColor.Color = Color.FromArgb(kolLos(), kolLos(), kolLos(), kolLos());
blueRectangle.Background = myColor;
However, every button has the same brush instance, so when you change the color for the next button, all the previous ones change as well.
You need to create a new brush:
SolidColorBrush backgorundBrush = new SolidColorBrush();
backgorundBrush.Color = Color.FromArgb(kolLos(), kolLos(), kolLos(), kolLos());
blueRectangle.Background = backgorundBrush;

How can I use a C# function to access the WPF control that called it?

I'm working on a game level editor in WPF using C#.
I have a series of image controls for choosing textures, and I want each image to be clickable, with some visible feedback to show which one is selected.
Here's one of the image controls, along with a green highlight border that shows up when it's clicked:
<Image x:Name="tile_image1" Source="as asphalt_test.png" Stretch="Fill" HorizontalAlignment="Right" VerticalAlignment="Top" Width="50" Height="50" MouseDown="texture_click" Margin="0,93,69,0" RenderTransformOrigin="0.16,2.04"/>
<Border x:Name="tile_border" BorderBrush="Lime" BorderThickness="3" HorizontalAlignment="Right" Height="54" Margin="0,91,65,0" VerticalAlignment="Top" Width="54" Visibility="Hidden" />
My question involves the "texture_click" function.
I want to re-use the same function for each image control, which I can easily assign using the MouseDown attribute in XAML. However, what I don't know is how to tell from within the function which control called it, or how to access that control's property's, such as ".Source". I want to be able to grab the file name of the image, as well as move the coordinates of the green border behind the new selection.
Right now, I just have it hard-coded to the first image control. Clicks on the other images will call the function, but the function will only select the first image (not the one that was actually clicked).
// click on tile 1
private void texture_click (object sender, MouseButtonEventArgs e)
{
tile_border.Visibility = Visibility.Visible;
current_tilefile = tile_image1.Source;
string source_string = Convert.ToString (tile_image1.Source);
int last_slash = source_string.LastIndexOf ('/');
current_tile = source_string.Substring (last_slash + 1, 3);
}
I tried using "sender", since I thought that might be the object that called the function, but that returned an error. I also tried calling the function with "texture_click (this)", but that was also no good. These were, admittedly, complete shots in the dark, so I wasn't surprised.
I'm still pretty new to this software, so any insight you guys can give would be great.
You just have to cast the sender parameter to the control type (Image in this case):
private void texture_click (object sender, MouseButtonEventArgs e)
{
//tile_border.Visibility = Visibility.Visible;
var image = sender as Image;
if (image != null)
{
current_tilefile = image.Source;
string source_string = image.Source.ToString();
int last_slash = source_string.LastIndexOf ('/');
current_tile = source_string.Substring (last_slash + 1, 3);
}
}
Of course, this doesn't give you access to the associated border. One thing you can do is to just dump the border into the Image's Tag property:
<Image x:Name="tile_image1" ... Tag="{Binding ElementName=tile_border}" />
<Border x:Name="tile_border" ... />
Then you can retrieve it, again by casting:
private void texture_click (object sender, MouseButtonEventArgs e)
{
var image = sender as Image;
if (image != null)
{
var border = image.Tag as Border;
if (border != null)
{
border.Visibility = Visibility.Visible;
}
// ...
}
}
Note that this (manipulating UI elements from code-behind) is not the ideal way to write a WPF application. Typically you would do something like this by using an existing control (like a ToggleButton), and re-writing its ControlTemplate so that its IsChecked visual state shows a border. But I realize that is a mouthful ...

Parameter to an image

How to add a parameter for an image to this variable?
var selectionDisplay = new SelectionDisplay(button.Label as string);
Thanks in advance!
EDIT:
I have this set of images and their respective code below (see pic1)
This is where the program gets the images to be displayed. The code for the buttons is this one:
var files = Directory.GetFiles(#".\GalleryImages");
foreach (var file in files)
{
FileInfo fileInfo = new FileInfo(file);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(file, UriKind.Relative);
bi.EndInit();
var button = new KinectTileButton
{
Label = System.IO.Path.GetFileNameWithoutExtension(file),
Background = new ImageBrush(bi)
};
this.wrapPanel.Children.Add(button);
}
This is where the program gets the images to be displayed.
The code for the buttons is this one:
private void KinectTileButtonclick(object sender, RoutedEventArgs e)
{
var button = (KinectTileButton)e.fake_fake_fakeource;
var selectionDisplay = new SelectionDisplay(button.Label as string);
this.kinectRegionGrid.Children.Add(selectionDisplay);
e.Handled = true;
Right now, when i click on of the images, the SelectionDisplay window pops up, which look like this (see pic2). What i want is that when I click an image the SelectionDisplay window should open with the respective image... meaning that if I click on the image with a dog, the window should open with the dog's image, not with other image.
I hope I've made myself clear and that you can help me.
http://i58.tinypic.com/8zl6h3.jpg
http://i57.tinypic.com/208fosy.png
is this the constructor you are talking about? is this where i should make changes? should i add something after "string itemid"?
public SelectionDisplay(string itemId)
{
this.InitializeComponent();
this.messageTextBlock.Text = string.Format(CultureInfo.CurrentCulture,Properties.Resources.SelectedMessage,itemId);
}
I see two approaches:
Just pass the image brush in your constructor. Its view->view, so you aren't breaking MVVM (and it looks like you aren't using that pattern anyways).
new SelectionDisplay(button.Label, button.Background);
Set the path as the "tag" of the button. The tag property is an object you can put whatever you want into (the framework does not use it, and so it is included for this very purpose). Then just pass the string to SelectionDisplay, and instantiate the image just like you are doing for the button:
var button = new KinectTileButton
{
Label = System.IO.Path.GetFileNameWithoutExtension(file),
Background = new ImageBrush(bi),
Tag = file
};
var selectionDisplay = new SelectionDisplay(button.Label as string, button.Tag as string);
FrameworkElement.Tag on MSDN (Note that Button derives from FrameworkElement, as do all controls, so it automatically has it as well!)
UPDATE
I see that SelectionDisplay is a UserControl in your project, so you just need to change its constructor to look like:
Numbers match above:
SelectionDisplay(string labelText, ImageBrush sourceImage)
SelectionDisplay(string labelText, string imagePath)
That is the source of the error you are getting, you have to modify the constructor to take the new parameter.
Please let me know if I can clarify anything.

Adding image to a button in WPF C#, image not appearing

I want to create a button in my windows 8 desktop app, which will have an image and a text block. I have to do this using C# coding.
My code is as follows,
Button btn = new Button();
StackPanel btnContentPanel = new StackPanel();
btnContentPanel.Orientation = Orientation.Horizontal;
Image img = new Image();
img.Source = new BitmapImage(newUri(#"C:\Users\Desktop\Images\download.jpg"));
img.Stretch = Stretch.Uniform;
btnContentPanel.Children.Add(img);
TextBlock txBlock = new TextBlock();
txBlock.Text = "My Button";
btnContentPanel.Children.Add(txBlock);
btn.Content = btnContentPanel;
This is not giving any error but the image is not getting displayed. If I add another text block in place of the image, then its appearing, but not the image.
Am I missing anything ? Please help, thank you.
Try building your button like this:
Button btn= new Button
{
Width = 30,
Height = 30,
Content = new Image
{
Source = new BitmapImage(#"C:\Users\Desktop\Images\download.jpg"))
}
};
In the case of a 'missing' image there are several things to consider:
When Xaml can't locate a resource it might ignore it (when it won't throw a XamlParseException)
The Resource must be properly added and defined:
make sure it exists in your project where expected.
Make sure it is built with your project as a Resource.
(Right click -> Properties -> BuildAction='Resource')
Another thing to try in similar cases, which is also useful for reusing of the image (or any other resource):
Define your Image as a Resource in your Xaml:
<UserCondrol.Resources>
<Image x:Key="MyImage" Source.../>
</UserControl.Resources>
And later use it in your desired control/controls:
<Button Content={StaticResource MyImage} />

Categories

Resources