Image not displaying XAML - c#

I created my own button that has Icon on the side and text on the other but the problem is the image is not displaying. did i miss something here? any help would be appreciated. TIA
This is the XAML of the control.
<UserControl x:Name="QButtonControl"
x:Class="CommonLayout.QButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CommonLayout"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="36"
d:DesignWidth="145" MinWidth="145" MinHeight="36" Loaded="QButtonControl_Loaded">
<Grid PointerEntered="Grid_PointerEntered_1" PointerExited="Grid_PointerExited_1" MinWidth="145" MinHeight="36" Background="#FFDCD1D1">
<TextBlock x:Name="btnLabel" Height="20" Margin="36,8,4,8" TextWrapping="Wrap" Text="Text Here" VerticalAlignment="Center" FontSize="18.667" Width="105"/>
<Image x:Name="img" HorizontalAlignment="Left" Height="27" Margin="1,4,0,0" VerticalAlignment="Top" Width="29"/>
</Grid>
</UserControl>
This is code behind the control.
public sealed partial class QButton : UserControl
{
private ImageSource iconDefault;
private Brush hoverBrush = new SolidColorBrush(Color.FromArgb(255, 228, 228, 228));
public string Text
{
get
{
return btnLabel.Text;
}
set
{
btnLabel.Text = value;
}
}
public ImageSource Icon
{
get
{
return iconDefault;
}
set
{
iconDefault = value;
img.Source = value;
}
}
public Brush HoverBrush
{
get
{
return hoverBrush;
}
set
{
hoverBrush = value;
}
}
public QButton()
{
this.InitializeComponent();
}
private void Grid_PointerEntered_1(object sender, PointerRoutedEventArgs e)
{
btnLabel.Foreground = HoverBrush;
}
private void Grid_PointerExited_1(object sender, PointerRoutedEventArgs e)
{
btnLabel.Foreground = Foreground;
}
private void QButtonControl_Loaded(object sender, RoutedEventArgs e)
{
img.Source = iconDefault;
}
}

First of all, do not use a hard coded file path to the image.
Windows Store apps run in a sandbox, so you will not be able to get to any arbitrary file location when you deploy your app.
Second, you can't use backslashes in Image URI. The backslashes are the technical reason you are setting the error you are getting. But just changing to forward slashes in not the answer.
Access Image in XAML
If you add an image to your projects /Assets folder, you can use XAML like this to show it in QButton.
<local:QButton x:Name='qButton1'
Icon='/assets/jellyfish.jpg' />
In Code
To change the Icon in code.
public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
}
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/shrimp.jpg"));
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
var image = new BitmapImage();
image.SetSource(fileStream);
qButton1.Icon = image;
}
If you want the user to choose the Image from their computer at runtime, look at the File Pickers.
MSDN file pickers

Are you forgetting to set the Icon property?
This worked for me
<local:QButton Icon="C:\Users\Public\Pictures\Sample Pictures\Penguins.jpg" />
This worked as well
public QButton()
{
this.InitializeComponent();
Uri imageUri = new Uri(#"C:\Users\Public\Pictures\Sample Pictures\Penguins.jpg");
BitmapImage image = new BitmapImage(imageUri);
this.Icon = image;
}

Related

Cannot Binding ImageSource in Content Dialog UWP

I put image in Content Dialog but I cannot see any image fetched from the source. It seems that the image source cannot binding from the view model. However it works well with Page
This is my XAML of Content Dialog
<ContentDialog
x:Class="SmartEducation.App.Teacher.ContentViewer.Views.SketchDetailPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SmartEducation.App.Teacher.ContentViewer.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uwpControls="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d"
Title="Student's Sketch"
CloseButtonText="Cancel"
DefaultButton="Primary"
Background="White" Width="750" Height="500">
<RelativePanel>
<ScrollViewer x:Name="scrollView" ZoomMode="Enabled" DoubleTapped="ScrollViewer_DoubleTapped" HorizontalScrollBarVisibility="Visible" HorizontalScrollMode="Enabled" MinZoomFactor="1">
<StackPanel Background="White" Width="750" Height="500">
<Image Name="imgSketch" Source="{Binding ImageUri}"/>
</StackPanel>
</ScrollViewer>
</RelativePanel>
I already add ViewModel to DataContext in my xaml.cs
private SketchDetailPageViewModel ViewModel
{
get { return DataContext as SketchDetailPageViewModel; }
}
public SketchDetailPage()
{
this.InitializeComponent();
}
I put the ImageUri in my ViewModel
private string _imgContent;
public string ImageUri
{
get { return _imgContent; }
set
{
_imgContent = value;
OnPropertyChanged(nameof(ImageUri));
}
}
Firstly, please make sure the ImageUri has an image resource reference. In your xaml.cs code, just providing a ViewModel property by your following code can not set the dialog's data context, so it will not get the image source.
private SketchDetailPageViewModel ViewModel
{
get { return DataContext as SketchDetailPageViewModel; }
}
You can just configure the dialog's data context by the following code in the dialog's xaml.cs,
public SketchDetailPage()
{
this.InitializeComponent();
this.DataContext = new SketchDetailPageViewModel() { ImageUri= "ms-appx:///Assets/Image.png" };
}
If you put the image source in the ViewModel. Such as,
private string _imgContent= "ms-appx:///Assets/Image.png";
public string ImageUri
{
get { return _imgContent; }
set
{
_imgContent = value;
OnPropertyChanged(nameof(ImageUri));
}
}
Then you can set the page data context on the XAML of Content Dialog,
<ContentDialog
...
Background="White" Width="750" Height="500">
<ContentDialog.DataContext>
<local:SketchDetailPageViewModel/>
</ContentDialog.DataContext>
<RelativePanel>
<ScrollViewer x:Name="scrollView" ZoomMode="Enabled"
DoubleTapped="ScrollViewer_DoubleTapped"
HorizontalScrollBarVisibility="Visible"
HorizontalScrollMode="Enabled"
MinZoomFactor="1">
<StackPanel Background="White" Width="750" Height="500">
<Image Name="imgSketch" Source="{Binding ImageUri}"/>
</StackPanel>
</ScrollViewer>
</RelativePanel>
</ContentDialog>
Or you can set the data context in the xaml.cs,
public SketchDetailPage()
{
this.InitializeComponent();
this.DataContext = new SketchDetailPageViewModel();
}
------ Update ------
but the binding image uri doesn't change although image uri of source change
If you want to change the image by changing the image uri, you can expose the dialog's data context as the following code, meanwhile, your SketchDetailPageViewModel should implement the INotifyPropertyChanged interface. It seems you have implement the interface, here is a simple example,
SketchDetailPageViewModel class,
internal class SketchDetailPageViewModel : INotifyPropertyChanged
{
private string _imgContent;
public string ImageUri
{
get { return _imgContent; }
set
{
_imgContent = value;
OnPropertyChanged(nameof(ImageUri));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
class SketchDetailPage : ContentDialog,
public SketchDetailPage()
{
this.InitializeComponent();
this.DataContext = new SketchDetailPageViewModel() { ImageUri= "ms-appx:///Assets/Image.png" };
}
internal SketchDetailPageViewModel ViewModel
{
get { return DataContext as SketchDetailPageViewModel; }
}
you can change the image when you use the SketchDetailPage dialog,
private async void Button_Click(object sender, RoutedEventArgs e)
{
SketchDetailPage dialog = new SketchDetailPage();
//change the dialog image
dialog.ViewModel.ImageUri = "ms-appx:///Assets/StoreLogo.png";
await dialog.ShowAsync();
}

UWP Viewbox and Flipview Manipulations

I'm writing a UWP photo viewer app that has a custom control that contains a Viewbox and has custom ManipulationEvents, inside a FlipView. I want to make it so that when you are zoomed out all the way you can swipe to flip, but still able to zoom in. That's where my problem is.
When I have the viewbox set to anything except ManipulationMode = ManipulationModes.System, dragging on the viewbox does not trigger the FlipView. The problem is I want to be able to still zoom in on the image when in zoom level 1.
Basically I'd like to set something that looks like: ManipulationMode="Scale, System", where everything that's not scale would be bubbled up. Or even trigger this in code-behind.
How would I accomplish this?
Here is the basis of what I am doing:
CustomControl.xaml
<UserControl ...>
<Grid>
<ScrollViewer ...
ManipulationMode="System">
<Viewbox ManipulationMode="TranslateX, TranslateY, Rotate, Scale"
ManipulationStarted="Viewbox_OnManipulationStarted"
ManipulationDelta="Viewbox_ManipulationDelta">
<ContentControl Content="{Binding ElementName=MyControl, Path=ViewboxContext}" />
</Viewbox>
</ScrollViewer>
</Grid>
CustomControl.xaml.cs
...
void ViewboxHost_OnManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
...
}
void ViewboxHost_OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
if (IsAtMinZoom && e.Delta.Scale <= 1)
{
e.Handled = false;
} else {
e.Handled = true;
return;
}
...
}
MainPage.xaml
<Page ...>
<Grid>
<FlipView>
<FlipView.Items> <!-- These will later be added view ItemsSource -->
<FlipViewItem>
<controls:CustomControl>
<Image src="..." />
</controls:CustomControl>
</FlipViewItem>
<!-- More of these guys --->
</FlipView.Items>
</FlipView>
</Grid>
If I have correctly understand your question, you want to show a picture in each FlipViewItem, and this picture can be zoomed. When FlipView works on mobile, it can be swiped between items, and you want to make sure, this FlipView can only be swiped when the iamge's ZoomFactor = 1.
Here I wrote a sample to solve this problem, I didn't use any ViewBox and UserControl here, if you need to use them, you can change the DataTemplate in my sample:
<FlipView x:Name="flipView" ItemsSource="{x:Bind mylist}">
<FlipView.ItemTemplate>
<DataTemplate>
<ScrollViewer ZoomMode="Enabled" MinZoomFactor="1" MaxZoomFactor="4" PointerPressed="ScrollViewer_PointerPressed">
<Image Source="{Binding ImageSource}" Stretch="Uniform" />
</ScrollViewer>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
code behind:
private ObservableCollection<MyFlipViewItem> mylist = new ObservableCollection<MyFlipViewItem>();
public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
mylist.Clear();
mylist.Add(new MyFlipViewItem { ImageSource = "Assets/1.jpeg" });
mylist.Add(new MyFlipViewItem { ImageSource = "Assets/1.jpeg" });
mylist.Add(new MyFlipViewItem { ImageSource = "Assets/1.jpeg" });
mylist.Add(new MyFlipViewItem { ImageSource = "Assets/1.jpeg" });
}
private ScrollViewer flipviewscrollviewer;
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
flipviewscrollviewer = FindChildOfType<ScrollViewer>(flipView);
}
public static T FindChildOfType<T>(DependencyObject root) where T : class
{
var queue = new Queue<DependencyObject>();
queue.Enqueue(root);
while (queue.Count > 0)
{
DependencyObject current = queue.Dequeue();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(current); i++)
{
var child = VisualTreeHelper.GetChild(current, i);
var typedChild = child as T;
if (typedChild != null)
{
return typedChild;
}
queue.Enqueue(child);
}
}
return null;
}
private void ScrollViewer_PointerPressed(object sender, PointerRoutedEventArgs e)
{
var itemscrollviewer = sender as ScrollViewer;
if (itemscrollviewer.ZoomFactor != 1)
{
flipviewscrollviewer.HorizontalScrollMode = ScrollMode.Disabled;
}
else
{
flipviewscrollviewer.HorizontalScrollMode = ScrollMode.Enabled;
}
}
The MyFlipViewItem class:
public class MyFlipViewItem
{
public string ImageSource { get; set; }
}
Here in my sample you can see that I used PointerPressed event to detect if the manipulation is started. For the reason, you can refer to my other case: ListView ManipulationCompleted event doesn't work on phone.

Displayed image in UI locks the source file

I have a DataTemplate which was created from here:
ComboBoxes sharing Observable Collection keeps breaking
<UserControl.Resources>
<DataTemplate x:Key="ImageItemTemplate">
<StackPanel Orientation="Horizontal">
<Image Height="44" Source="{Binding Path}"/>
<Label Content="{Binding Name}" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<ComboBox x:Name="image1" ItemTemplate="{StaticResource ImageItemTemplate}"/>
Code:
public ObservableCollection<ImageItem> images = new ObservableCollection<ImageItem>();
Generic.ImportGrfx(tabID, image1, images);
public static void ImportGrfx(string tabID, ComboBox combo, ObservableCollection<ImageItem> items)
{
items.Clear();
try
{
string root = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
var files = Directory.GetFiles(Path.Combine(root, "input\\" + tabID), "*.png");
foreach (var file in files)
{
ImageItem item = new ImageItem();
item.Path = file;
item.Name = Path.GetFileName(file).Remove(Path.GetFileName(file).Length - 4);
items.Add(item);
}
}
catch (Exception) { }
combo.ItemsSource = items;
}
public class ImageItem
{
public string Path { get; set; }
public string Name { get; set; }
}
The problem I am having is binding these images to the datatemplate, "locks" the image source. Meaning I can't edit the images while the program is running... I would get an error stating the image is in use. Is there a way to fix this?
Here's a skeleton of an Image that will get updated whenever you modify it from outside.
you set the source, it copies it to a temp path and loads the image from there
it watches for changes in initial image and updates itself again
rinse and repeat :D
You can, not use the auto-update feature if you only need the ability to edit the image from outside.
It's really basic so feel free to improve ...
Code:
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
namespace WpfApplication4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
DynamicImage1.SetSource(#"d:\Untitled.png");
}
}
internal class DynamicImage : Image
{
private string _name;
private FileSystemWatcher _watcher;
public void SetSource(string fileName)
{
if (fileName == null) throw new ArgumentNullException("fileName");
if (_watcher != null)
{
_watcher.Changed -= watcher_Changed;
_watcher.Dispose();
}
string path = Path.GetDirectoryName(fileName);
_watcher = new FileSystemWatcher(path);
_watcher.EnableRaisingEvents = true;
_watcher.Changed += watcher_Changed;
_name = fileName;
string tempFileName = Path.GetTempFileName();
File.Copy(fileName, tempFileName, true);
Source = new BitmapImage(new Uri(tempFileName));
}
private void watcher_Changed(object sender, FileSystemEventArgs e)
{
bool b = string.Equals(e.FullPath, _name, StringComparison.InvariantCultureIgnoreCase);
if (b)
{
string tempFileName = Path.GetTempFileName();
File.Copy(e.FullPath, tempFileName, true);
Dispatcher.BeginInvoke((Action) (() => { Source = new BitmapImage(new Uri(tempFileName)); }));
_name = e.FullPath;
}
}
}
}
XAML:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication4="clr-namespace:WpfApplication4"
Title="MainWindow" Height="350" Width="525">
<Grid>
<wpfApplication4:DynamicImage x:Name="DynamicImage1" />
</Grid>
</Window>

How to send information from one window to another? WPF

How do I send information from one wpf window to another window. What I wanted is for string filepath to save the information it gets the first time it is called.
This is the problem, when I click button1 from window1.xmal.cs it calls openfile() from DocumentManager.cs. And when I access filepath from window2.xmal.cs it gives an empty string. I want to save the filepath string I got from when it was called from window1.xmal.cs.
Here is what I have:
window1.xmal.cs
DocumentManager mgr = new DocumentManager();
private void Button1_Click(object sender, RoutedEventArgs e) {
ImageSource imgsource = new BitmapImage(new Uri(mgr.openfile().ToString()));
themeImage.Source = imgsource;
}
DocumentManager.cs
public string filePath;
public object openfile() {
OpenFileDialog open = new OpenFileDialog();
bool? result = open.ShowDialog();
if (result == true) {
filePath = open.FileName;
}
return filePath;
}
I think your problem is the way you are instantiating the DocumentManager class.
I've made an example that works. Here's the code:
MainWindow
public partial class MainWindow : Window
{ DocumentManager mgr;
Window2 w2;
public MainWindow() { InitializeComponent(); }
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{ mgr = new DocumentManager(); w2 = new Window2(); w2.Show(); }
private void Button_Click(object sender, RoutedEventArgs e)
{ ImageSource imgsource; string imglocation;
try {
imglocation = mgr.openfile().ToString();
imgsource = new BitmapImage(new Uri(imglocation));
result.Text = imglocation;
w2.imgsource = imgsource;
}
catch (Exception ex)
{ System.Windows.MessageBox.Show(ex.Message); }
}
}
DocumentManager
class DocumentManager
{
public string filePath;
public string openfile()
{
Microsoft.Win32.OpenFileDialog open = new Microsoft.Win32.OpenFileDialog();
bool? result = open.ShowDialog();
if (result == true) { filePath = open.FileName; }
else { filePath = "Nothing Opened"; }
return filePath;
}
}
MainWindow XAML
<Window x:Class="CrossClassDialog.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="120" Width="350" Loaded="MainWindow_Loaded">
<Grid>
<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Top" Click="Button_Click"/>
<TextBlock x:Name="result" HorizontalAlignment="Left" Text="TextBlock" VerticalAlignment="Top" Margin="0,30,0,0"/>
</Grid>
</Window>
Window2 XAML
<Window x:Class="CrossClassDialog.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300">
<Grid>
<Viewbox HorizontalAlignment="Left" VerticalAlignment="Top">
<Image x:Name="OpenedImage" Source="{Binding ImageSource}" />
</Viewbox>
</Grid>
</Window>
Add this property in Window2
private ImageSource _imgsource;
public ImageSource imgsource
{
get { return _imgsource; }
set
{
_imgsource = value;
OpenedImage.Source = value;
}
}
By the way, I changed a few things like the type your openfile() method returns.

How do I get an animated gif to work in WPF dictionary without codebehind?

I have a dictionary that uses a datatemplate of another class,
the dictionary doen't have a code behind it's just XAML
i need to have a live animated gif as a part of this dictionary.
tried to do this:
var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("myprojectname.Resources.theGifToUse.gif");
System.Drawing.Image image = System.Drawing.Image.FromStream(stream);
picturebox = image;
and in the XAML:
<WindowsFormsHost>
<forms:PictureBox x:Name="pictu1rebox" Image="{Binding picturebox}"/>
</WindowsFormsHost>
but it doesn't work!
what is the most simple way to do it not using WpfAnimatedGif.dll?
thanks alot
Standard BitmapImage does not support playback of .gif files. The only option that I know is to use a Bitmap. It has ImageAnimator. Full example:
XAML
<Window x:Class="PlayGifHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="MainWindow_Loaded">
<Grid>
<Image x:Name="SampleImage" />
</Grid>
</Window>
Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
Bitmap _bitmap;
BitmapSource _source;
private BitmapSource GetSource()
{
if (_bitmap == null)
{
string path = Directory.GetCurrentDirectory();
// Check the path to the .gif file
_bitmap = new Bitmap(path + #"\anim.gif");
}
IntPtr handle = IntPtr.Zero;
handle = _bitmap.GetHbitmap();
return Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_source = GetSource();
SampleImage.Source = _source;
ImageAnimator.Animate(_bitmap, OnFrameChanged);
}
private void FrameUpdatedCallback()
{
ImageAnimator.UpdateFrames();
if (_source != null)
{
_source.Freeze();
}
_source = GetSource();
SampleImage.Source = _source;
InvalidateVisual();
}
private void OnFrameChanged(object sender, EventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(FrameUpdatedCallback));
}
}
Bitmap does not support URI directive, so I load .gif file from the current directory.

Categories

Resources