I'm creating a simple windows store app in c#. When i'm binding my image control to display an image from code- behind, my screen goes black. Anyone know how i can solve the problem?
ImageService Class
public class ImageService
{
public Image Image { get; set; }
public ImageService()
{
var uri = new System.Uri("ms-appx:///assets/Logo.scale-100.png");
var bmp = new BitmapImage(uri);
Image.Source = bmp;
}
}
XAML file
<Image x:Name="image" HorizontalAlignment="Left" Height="223" Margin="394,279,0,0" VerticalAlignment="Top" Width="305" Source="{Binding Image, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Stretch="UniformToFill"/>
Use this:
public class ImageService
{
public Uri Image { get; set; }
public ImageService()
{
Image = new Uri("ms-appx:///assets/Logo.scale-100.png");
}
}
The Source property of an Image is of type ImageSource which can be easily replaced by a Uri. (MSDN).
Images in XAML have a built in converter so you can just bind to a Uri, you don't have to create an Image in the service.
Your service isn't implementing INotifyPropertyChanged so if you set your image in your service outside the constructor your view won't update.
I don't see in your code where you are instantiating your Image. Image will be null so when your view loads, the Image will be null resulting in a blank image on your view.
You mean like this? Cause it still makes the sceen go black.
public class ImageService : INotifyPropertyChanged
{
private Uri _uri;
public Uri Uri
{
get { return _uri; }
set
{
_uri = value;
OnPropertyChanged();
}
}
public ImageService()
{
Uri = new Uri("ms-appx///assets/Logo.scale-100.png");
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Related
After searching far and wide, and getting nowhere, I decided to ask.
I have a .NET 5.0 WPF project I am working on, and I have to bind an URL (of an online image) to the source of an image on my form.
I have tried the following:
CoverImage.Source = new BitmapImage("https://somesite..com/img.png");
as well as binding it via XAML:
///XAML:
<Image Name="CoverImage"
Source="{Binding PreviewSource}"/>
///C#
public string PreviewSource { get; set; } = "https://somesite..com/img.png";
I have tried other solutions such as getting the image from a HrrpRequest and then creating it through a MemoryStream.
Using local images (that are on the pc) works without issues.
EDIT: mm8's solution started working for seemingly no reason (I have not touched the code at all since first testing)
new BitmapImage(new Uri("https://www.google.se/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png"))`
and
<Image Name="CoverImage" Source="https://www.google.se/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png"/>
...works just as expected on .NET 5.
Make sure that your URL is valid and reachable from your client machine.
Are you sure the datacontext is correct? It works for me in the app below.
Xaml Code
<Grid>
<Image Name="CoverImage" Source="{Binding ImageSource}"/>
</Grid>
ViewModel
class MainWindowViewModel : ViewModelBase
{
private BitmapImage _imageSource;
public BitmapImage ImageSource
{
get => _imageSource;
set => SetProperty(ref _imageSource, value);
}
public MainWindowViewModel()
{
ImageSource = new BitmapImage(new Uri("https://www.google.se/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png"));
}
}
ViewModelBase
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual bool SetProperty<T>(ref T member, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(member, value))
{
return false;
}
member = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
MainWindow.xaml.cs
public MainWindow()
{
DataContext = new MainWindowViewModel();
InitializeComponent();
}
I have a question. How to bind variables dynamically from ViewModel to View? For now, it not even displayed. If i not using Command, it works great (but of course, i can bind image only once).
My View:
namespace somestuff.View
{
public partial class WindowView : Window
{
public WindowView()
{
this.DataContext = new WindowViewModel();
InitializeComponent();
}
}
}
my View.Xaml (shorten):
<Image Source="{Binding DisplayedImage}"/>
<Button Command="{Binding NewImageCommand}"/>
And my ViewModel:
public WindowViewModel()
{
_canExecute = true;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string DisplayedImage //displaying image
{
get { return filepath; }
set { filepath = value; NotifyPropertyChanged(nameof(filepath)); }
}
public string filepath { get; set; } //var for binding
private bool _canExecute;
private ICommand _newImageCommand; //command for button
public ICommand NewImageCommand
{
get
{
return _newImageCommand ?? (_newImageCommand = new Commands.CommandHandler(() => GetImage(), _canExecute));
}
}
public void GetImage() { filepath = Pictures.GetNewImage(); } //command on button click
Can you tell me, why after triggering Command GetImage() on button click the image binded on Image not changed? If i move filepath = Pictures.GetNewImage(); from command (more clear, i not use command) all works great, but i cant re-invoke binding to my Image. Can you tell me, how to bind propertis dynamically into View from View model? When value of variable (in this case, filepath) change, i want to change View control too.
Thanks for any advices.
EDIT:
I have 6 Image Labels. I displaying images in it like that:
public BitmapImage DisplayedHighPerformanceImage
{
get { return kMMHP; }
set { kMMHP = value; NotifyPropertyChanged(nameof(kMMHP)); }
}
So i need filepath to init 6 diffrent bitmaps. Then i work on that bitmaps (for exampe, that kMMHP) So i want to display every new bitmap initialized from kMMHP image.
kMMHP = method1(); //displaying it
//other stuff do with diffrent bmps
kMMHP = method2(); //displaying it after second method with changed values
NotifyPropertyChanged must be called with the name of the property, not the name of its backing field. And in order to fire the change notification event, you have to set the property, not the backing field:
public BitmapImage DisplayedHighPerformanceImage
{
get { return kMMHP; }
set { kMMHP = value; NotifyPropertyChanged(nameof(DisplayedHighPerformanceImage)); }
}
DisplayedHighPerformanceImage = method1();
I need to refresh Image on View
This my ViewPage:
<Image Grid.Row="1"
Grid.Column="1"
x:Name="OriginalImg"
Source="{Binding Orig}"
DataContext="{StaticResource MainViewModel}"/>
I'm using MVVMLibs package. And This is my ViewModel:
public class MainViewModel: ViewModelBase
{
private WriteableBitmap original = new WriteableBitmap(1280,720);
private WriteableBitmap temp = new WriteableBitmap(1280,720);
public WriteableBitmap Orig
{
get { return original; }
set
{
this.original = value;
base.RaisePropertyChanged("Orig");
}
}
public async Task<bool> ApplyEffectAsync(StorageFile file)
{
fileStream = await file.OpenAsync(FileAccessMode.Read);
temp.SetSource(fileStream);
Orig = temp;
}
}
But Image on my Page not displayed. What's my problem?
Problem is you are not really instantiating a new WriteableBitmap, just changing its source. So while it might work the first time, it certainly won't work after because the Dependency Property Manager won't know that your image changed unless its instace changes.
Try creating your temp WriteableBitmap in the ApplyEffectAsync method.
I want to bind a TextBlock to a string which takes its value from a txt file. The string is correctly filled but its contents are not displayed.
Class file:
public partial class JokesMessageBox : Window
{
public JokesMessageBox()
{
InitializeComponent();
}
public string Joke { get; set; }
public string path = "data/jokes.txt";
public void ReadFile(string path)
{
Joke = File.ReadAllText(path);
}
}
XAML:
<TextBlock HorizontalAlignment="Left" Margin="22,10,0,0"
TextWrapping="Wrap" Text="{Binding Joke}" VerticalAlignment="Top"
Height="60" Width="309"/>
EDIT:
In the MainWindow class:
private void btnJokesFirstScreen_Click_1(object sender, RoutedEventArgs e)
{
JokesMessageBox jkb = new JokesMessageBox();
jkb.Show();
jkb.ReadFile("data/jokes.txt");
}
I spent 3+ hours on google, youtube, MSDN, StackOverflow and still can't get it working. What am I missing?
If the you need to update the binding, the property Joke must be a DependencyProperty or the Windows must implement INotifyPropertyChanged interface.
On the view, the binding needs to know Source.
Example #1 (Using DependencyProperty):
public partial class JokesMessageBox : Window
{
public JokesMessageBox()
{
InitializeComponent();
ReadFile(Path); //example call
}
public string Joke
{
get { return (string)GetValue(JokeProperty); }
set { SetValue(JokeProperty, value); }
}
public static readonly DependencyProperty JokeProperty =
DependencyProperty.Register("Joke", typeof(string), typeof(JokesMessageBox), new PropertyMetadata(null));
public const string Path = "data/jokes.txt";
public void ReadFile(string path)
{
Joke = File.ReadAllText(path);
}
}
Example #2 (Using INotifyPropertyChanged interface):
public partial class JokesMessageBox : Window, INotifyPropertyChanged
{
public JokesMessageBox()
{
InitializeComponent();
ReadFile(Path); //example call
}
private string _joke;
public string Joke
{
get { return _joke; }
set
{
if (string.Equals(value, _joke))
return;
_joke = value;
OnPropertyChanged("Joke");
}
}
public const string Path = "data/jokes.txt";
public void ReadFile(string path)
{
Joke = File.ReadAllText(path);
}
//INotifyPropertyChanged members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
And the view (XAML partial):
...
<TextBlock HorizontalAlignment="Left" Margin="22,10,0,0"
TextWrapping="Wrap"
Text="{Binding Joke,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"
VerticalAlignment="Top"
Height="60" Width="309"/>
...
I hope it helps.
When you read the contents of the file, you assign the read string to your Joke property:
Joke = File.ReadAllText(path);
The Text property of the TextBlock is indeed bound to that property (if you have properly set the data context):
Text="{Binding Joke}"
However, what is missing is that the binding cannot possibly have any idea that the property value has changed. You need to issue a notification about the property change.
There are two ways to do this that will be recognized by WPF bindings:
You declare your Joke property as a dependency property. This is based on some WPF infrastructure that automatically issues the change notifications.
You have your class implement the INotifyPropertyChanged interface. Here, you have to implement a simple interface with a PropertyChanged event, which you have to fire in your property setter while passing the name of the property as a string.
Your class is not implementing INotifyPropertyChanged interface. So when you change property Joke TextBlock is not updated. I would do something like this:
public partial class JokesMessageBox : Window, INotifyPropertyChanged
{
public JokesMessageBox()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
public string Joke { get; set; }
public string path = "data/jokes.txt";
public void ReadFile(string path)
{
Joke = File.ReadAllText(path);
OnPropertyChanged("Joke");
}
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I would also suggest you to read about MVVM patern.
I have a single ListBox that is supposed to display a picture with each item. I wrote codes and when I run it, pictures couldn't be displayed, but only text displayed. What have I done wrong in my codes? I made sure the image file path is correct.
I want to display each item with text (right side) and icon (left side).
WPF:
<ListBox Name="ListTest" DisplayMemberPath="Name" HorizontalAlignment="Left" Height="358" Margin="603,38,0,0" VerticalAlignment="Top" Width="361">
</ListBox>
C#
public partial class UserControl2 : UserControl
{
public UserControl2()
{
InitializeComponent();
this.LoadLogos();
}
private void LoadLogos()
{
this.ListTest.Items.Add(new CompanyDataContext("Adobe", "Adobe is a designing tool.", "/Company Logos/testDinner.jpg"));
this.ListTest.Items.Add(new CompanyDataContext("Facebook", "FedEx is a social networking website.", "/Company Logos/facebook.jpg"));
this.ListTest.Items.Add(new CompanyDataContext("FedEx", "FedEx is a courier company.", "/Company Logos/fedex.jpg"));
}
private class CompanyDataContext
{
public CompanyDataContext(string name, string about, string image)
{
this.Name = name;
this.About = about;
this.Image = image;
}
public string Name { get; private set; }
public string About { get; private set; }
public string Image { get; private set; }
}
}
You need a DataTemplate for CompanyDataContext as it does not inherit from Visual, WPF has no idea how to render it hence it calls the ToString Method on this.
This can be dealt with aDataTemplate for the ListBox
Untested template:
<ListBox.ItemTemplate>
<DataTemplate>
<Border x:Name="bord" CornerRadius="5" Margin="2" BorderBrush="LightGray" BorderThickness="3" Background="DarkGray">
<StackPanel Margin="5">
<TextBlock x:Name="txt" Text="{Binding Name}" FontWeight="Bold"/>
<Image Source="{Binding Image}" Height="100"/>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
Edited typo