I am fairly new to Windows Store Application Development. I am stuck at trying to change the image of the grid via c# code.
This is my Mainpage.Xaml code
<Grid x:Name="BG" KeyDown="operation" Width="1327" Height="740">
<Grid.Background>
<ImageBrush Stretch="UniformToFill" ImageSource="Assets/background.jpg"/>
</Grid.Background>
<Button x:Name="ThemeButton" BorderBrush="{x:Null}" FontSize="14" Content="Theme 1" Margin="25,0,0,0" HorizontalAlignment="Left" Click="ChangeBG"></Button>
This is my Mainpage.Xaml.cs Code
private void ChangeBG(object sender, RoutedEventArgs e)
{
ImageBrush b1 = new ImageBrush();
b1.ImageSource = new BitmapImage(new Uri(#"D:\Visual Studio Project File\Sadiqali Calculator\Sadiqali Calculator\Assets\Theme2.png"));
BG.Background = b1;
}
When the button is pressed I am getting a black background instead of the picture. The above code is from other threads.
How can I change the image source of the grid via code on click of a button?
Your code works fine here when I use my own images.
Check the location of D:\Visual Studio Project File\Sadiqali Calculator\Sadiqali Calculator\Assets\Theme2.png ... are you sure this is valid?
Also - ChangeBG will run on the UI thread if invoked from the button click.
Thank You Everyone! You have helped me solve it!
This is what I changed the code to and it worked.
ImageBrush b1 = new ImageBrush();
b1.ImageSource = new BitmapImage(new Uri(#"ms-appx:///Assets/Theme2.png", UriKind.RelativeOrAbsolute));
BG.Background = b1;
Related
I have a wpf application which helps customers choose a paint colour for their house. Please see image and code below.
code behind
private void REDBUTTONPICKER_Click(object sender, RoutedEventArgs e)
{
var brush = new ImageBrush();
brush.ImageSource = new BitmapImage(new Uri(#"c:\users\user1\documents\visual studio 2015\Projects\WpfApplication7\paintpicker\RED.jpg", UriKind.Relative));
REDCOLOURPREVIEW.Background = brush;
}
buttons
<Button x:Name="REDBUTTONPICKER" Content="RED" HorizontalAlignment="Left" Height="65" Margin="46,60,0,0" VerticalAlignment="Top" Width="79" Click="REDBUTTONPICKER_Click">
<Button.Background>
<ImageBrush ImageSource="c:\users\user1\documents\visual studio 2015\Projects\WpfApplication7\paintpicker\RED.jpg"/>
</Button.Background>
</Button>
when the customer clicks review I want the colours picked on the previous page to show in the boxes on the "YOUR CHOSEN COLOURS" page. Please see image below.
The four boxes are buttons.
One way of resolving this is to use the MVVM pattern where each of the chosen colors will be bound to properties on the VM. In the selection of the color, it will also set the current unset chosen color to change.
To get an understanding of MVVM I have written a blog article
Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding
which can get you started on creating a basic MVVM architecture to work with.
I have following code snippet in xaml:
<UserControl x:Class="Ournamespace.OurClassName"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
...
d:DesignHeight="250" d:DesignWidth="774" Loaded="UserControl_Loaded">
....
<Button Grid.Column="0" x:Name="Button_NewMarker" Style="{StaticResource ViewpointFlatButtonStyle}" Width="90" Height="65"
VerticalAlignment="Top" Click="Button_NewMarker_Click" x:FieldModifier="public" Margin="0,0,0,0" Grid.Row="1">
<BitmapImage UriSource="Icons/markers_add_disabled.png" />
</Button>
and I have tried to replace image on button dynamically, by loading new image
if( !imgCache.ContainsKey(path) )
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(path, UriKind.Relative);
bi.DownloadFailed += bi_DownloadFailed;
bi.DecodeFailed += bi_DecodeFailed;
bi.EndInit();
imgCache[path] = bi;
}
Button_NewMarker.BeginInit();
Button_NewMarker.Content = imgCache[path];
//Button_NewMarker.Content = oldbmp;
Button_NewMarker.EndInit();
There is no error occurring (overridden events for this)
and BitmapImage seems to be replaced - but for some reason it's grey.
Images are added to project as resources, and first image loaded seems to be working - but not dynamically replaced one.
I have tried also to use <Image ... > and even <Image ... <ImageBitmap - but all of them are not working - I suspect it has something to do with our control being UserControl.
What I have seen in internet - there is huge amount of recommendations of what and how should be done - I want now this to be done with absolute minimum amount of code - and preferably without using binding and templating. Binding can be proposed as second step after everything is done manually.
If image files are managed as resource files (i.e. project files which have their Build Action set to Resource) you should load them by a Resource File Pack URI.
Assuming a project folder Images with an image file Test.png:
var bi = new BitmapImage(new Uri("pack://application:,,,/Images/Test.png"));
Using the file name as key, the abobe would probably look like:
var path = "Test.png";
var uri = "pack://application:,,,/Images/" + path;
imgCache[path] = new BitmapImage(new Uri(uri));
I'm messing around with some windows phone development as I'm new to it coming from an Android background.
I am using "theCatAPI" to load a random picture of a cat and show it, then when the picture is clicked, or the button at the bottom of the screen, the image refreshes to a new one.
I have the following so far:
XAML:
<Page
x:Class="CatFactsPics.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CatFactsPics"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="LayoutRoot">
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</Grid.ChildrenTransitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- TitlePanel -->
<StackPanel Grid.Row="0" Margin="24,17,0,28">
<TextBlock Text="My Application" Style="{ThemeResource TitleTextBlockStyle}" Typography.Capitals="SmallCaps"/>
<TextBlock Text="page title" Margin="0,12,0,0" Style="{ThemeResource HeaderTextBlockStyle}"/>
</StackPanel>
<!--TODO: Content should be placed within the following grid-->
<Grid Grid.Row="1" x:Name="ContentRoot">
<Image HorizontalAlignment="Center" Stretch="UniformToFill" VerticalAlignment="Center" x:Name="KittyPic" Tapped="KittyPic_Tapped"/>
<Button HorizontalAlignment="Center" VerticalAlignment="Bottom" x:Name="newPic" Click="newPic_Click" >New Kitty</Button>
</Grid>
</Grid>
</Page>
and in the page.cs:
...
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.navigationHelper.OnNavigatedTo(e);
Uri myUri = new Uri("http://thecatapi.com/api/images/get?format=src&type=jpg", UriKind.Absolute);
KittyPic.Source = new BitmapImage(myUri);
}
...
private void newPic_Click(object sender, RoutedEventArgs e)
{
Uri myUri = new Uri("http://thecatapi.com/api/images/get?format=src&type=jpg", UriKind.Absolute);
BitmapImage bmi = new BitmapImage();
bmi.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
bmi.UriSource = myUri;
KittyPic.Source = bmi;
}
I have a couple of questions:
1) is this the correct way of doing things? In Android I'd try and do things asynchronously to avoid stalling the UI thread. That being said, I don't appear to be having any issues with things the way they are now. I'm not familiar with the Windows way of doing things, and haven't found any resources giving any explanation or advice on doing so.
2) There is a delay in displaying the new picture causing a short (couple of second) period where the image view turns black, before the new image reappears. Is there a way of setting it up so either the old picture remains until the new one is physically ready to be displayed, or alternatively display a placeholder "loading" image until the new one can replace it.
Any other advice or tips on how to do things would be great, thanks.
1) With your current code you do not block the UI thread as yes you are setting the URI on the UI thread, but the actually loading of the image is done on another thread automatically. (For doing manually downloading of images, strings etc, you will probably use async/await to avoid locking the UI thread).
2) The image goes black because you change the ImageSource before the new image has loaded. There are as you mention several ways to deal with this. Common for most of them though is that you will want to use the ImageOpened and ImageFailed events on the Image control, which triggers whenever the image is done loading (or an error occurred, for example no internet connection). Here is an example of displaying a loading bar while it is loading, which just hides/shows the loading progress:
In the page.xaml file:
<Grid Grid.Row="1" x:Name="ContentRoot">
<Image x:Name="KittyPic" Tapped="KittyPic_Tapped" ImageOpened="KittyPic_ImageOpened" ImageFailed="KittyPic_ImageFailed" />
<StackPanel x:Name="LoadingPanel" VerticalAlignment="Center">
<ProgressBar IsIndeterminate="True" IsEnabled="True" />
<TextBlock Text="Loading image..." HorizontalAlignment="Center" />
</StackPanel>
</Grid>
And in the page.xaml.cs file
private void KittyPic_Tapped(object sender, TappedRoutedEventArgs e)
{
LoadingPanel.Visibility = Visibility.Visible;
Uri myUri = new Uri("http://thecatapi.com/api/images/get?format=src&type=jpg", UriKind.Absolute);
BitmapImage bmi = new BitmapImage();
bmi.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
bmi.UriSource = myUri;
KittyPic.Source = bmi;
}
private void KittyPic_ImageOpened(object sender, RoutedEventArgs e)
{
LoadingPanel.Visibility = Visibility.Collapsed;
}
private async void KittyPic_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
LoadingPanel.Visibility = Visibility.Collapsed;
await new MessageDialog("Failed to load the image").ShowAsync();
}
Instead of the TextBlock and ProgressBar you could of course show whatever you want, or for example swapping between two images to keep showing the old one.
For other advice I think when you got used to the basics is to take a look at data bindings which is very helpful and powerful. Also take a look at this article about MVVM pattern.
1) is this the correct way of doing things?
No. It's not. You should definitely adopt the MVVM pattern and detach your business logic from your view - meaning you shouldn't create bitmap images or request/assign such remote image URL's in your view's code-behind. You should be doing such stuff in your ViewModel and bind them to your View.
So in your case there will be an Uri (or a string where you will assign the remote URL) property in your ViewModel (which implements INotifyPropertyChanged) then in your View you will be binding it like this:
<!--TODO: Content should be placed within the following grid-->
<Grid Grid.Row="1" x:Name="ContentRoot">
<BitmapImage UriSource="{Binding BackGroundImage}" CreateOptions="BackgroundCreation" />
<Button HorizontalAlignment="Center" VerticalAlignment="Bottom" x:Name="newPic" Click="newPic_Click" >New Kitty</Button>
</Grid>
Whenever you set the BackGroundImage property you will be raising an event called;
RaisePropertyChanged("BackGroundImage") -> This is the classical MVVM approach.
So that your view will be aware of the fact that the BackGroundImage is changed and it will load it automatically. (But note that if you just provide a string for this BackGroundImage - you will have to use a converter, a string to Uri converter, since it only accepts Uri's for remote images)
2) "...Is there a way of setting it up so either the old picture remains until the new one is physically ready to be displayed, or alternatively display a placeholder "loading" image until the new one can replace it."
I suggest going with displaying a 'loading' image. I experienced the exact same problem as you do here and my workaround for this was inserting a loading image and setting it's opacity value to 0.1 - along with the actual image. While you are switching between remote URL's, when the previous image disappears the opaque loading image appears and when the next actual image is loaded the loading image is not displayed because new image is overwriting it.
I have a Page like in the Xaml below which i want to use like a ModalDialog.
The Problem is that when I Pop the Dialog up, that the Opacity of the second Grid which holds the Content is not changed back to 100% and I see from the Page where it is Popuped the underlying controls. For more Detail see the Screenshot.
Is there a way that I can change back the Opacity of the second Grid to 100% that no control behind it can see through?
For completneness I have added the Code which i'm using to bring up the Popup.
ModalDialog Xaml:
<Page>
<Grid x:Name="RootPanel" Background="{StaticResource LucentBlue}" Opacity=".75">
<Border >
<Grid VerticalAlignment="Center"
Height="300" Background="{StaticResource PremiumBlue}" Opacity="1">
</Grid>
</Border>
</Grid>
</Page>
Code Behind Hosted Page:
private Popup _saveDialog;
private void SaveSettingsCommandLogic(object obj)
{
ModalDialog dlg = new ModalDialog();
dlg.CloseRequested += DlgOnCloseRequested;
_saveDialog = new Popup();
_saveDialog.Child = dlg;
_saveDialog.IsOpen = true;
}
Here's a solution in metro :
Please remove the Opacity property of both the elements and from the code behind of the ModalDialog class use the following code:
public ModalDialog()
{
this.InitializeComponent();
Color color = Color.FromArgb(150,255,0,0);
RootPanel.Background = new SolidColorBrush(color);
}
The method FromArgb is used to specify the transparency red green and blue values respectively and can rancge from 0-255 .. please test according to ur convinience :)
I'm creating buttons dynamically that have images as their background, The problem is the default WPF button animation on mouse over deform my button and hide the image.
Is there any way I can make my own button style for these buttons without creating a custom button class, and using something like myButtton.property = something;
in C# code not XAML because I'm creating the button dynamically.
YOu can do this by creating a template for button in resources...
Here is a sample...
XAML Code...
<UserControl.Resources>
<ControlTemplate x:Key="buttonTemplate">
<Image Name="btnImage" Source="C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"></Image>
</ControlTemplate>
</UserControl.Resources>
<Grid Name="layoutRoot">
</Grid>
</UserControl>
in code behind:
Button button = new Button();
ControlTemplate ct = this.Resources["buttonTemplate"] as ControlTemplate;
Image img = ct.LoadContent() as Image;
img.Source = new BitmapImage(new Uri(#"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg",UriKind.RelativeOrAbsolute));
button.Template = ct;
button.Height = 200;
button.Width = 200;
layoutRoot.Children.Add(button);
if you are adding buttons from view model you can get the button template from app resources (by putting the resource in app.xaml file)
You could set the ControlTemplate of the button. Since you do not wish to do this in the XAML here is one way you could do it in the code-behind:
string buttonTemplate =
"<ControlTemplate TargetType=\"Button\">" +
"<Image Source=\"myImage.gif\" />" +
"</ControlTemplate>";
myButton.Template = (ControlTemplate)XamlReader.Parse(template);
This is just for a basic button with an Image as the content. If you want to have custom animations on actions such as mouseover you can add XAML to the code-behind string using the VisualStateManager to take care of that.VisualStateManager