I have instantiated several System.Drawing.Icon Objects. Note that these are created at runtime and are not stored and loaded from the file system. I would like to place these images in my WPF application.
However as I have discovered over the last few hours, it is not possible to simply add an object such as an system.drawing.image or icon directly to the canvas/stack panel, nor is it possible to set the source of a System.Windows.Controls.Image to an image or icon not stored within the file system (or so it seems to me).
Any ideas?
This has worked for me dynamically setting a WPF Image with bytes loaded from a bitmap that was either dynamically generated or loaded from disk:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Drawing.Imaging;
namespace Examples
{
public class Util
{
private static void SetBitmap(Image imgDest, Bitmap bmpSource)
{
byte[] imageBytes;
using (MemoryStream stream = new MemoryStream())
{
bmpSource.Save(stream, ImageFormat.Png);
imageBytes = stream.ToArray();
}
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = new MemoryStream(imageBytes);
bitmapImage.EndInit();
imgDest.Source = bitmapImage;
}
}
}
Related
I want to display a window using a standard fade-in effect. Everything works well but the first time I load and show the window the fade in animation is not very smooth. If I close and show it again the animation works better.
Any way to improve the fade-in at the first time?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Animation;
namespace Kiosk
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
TimeSpan fadeTime = TimeSpan.FromMilliseconds(250);
var fadeInAnimation = new DoubleAnimation(1d, fadeTime);
BeginAnimation(Window.OpacityProperty, fadeInAnimation);
}
}
}
failing to follow a begiiner example: create a interactove sphere with ILNumerics. I added the nuget package as reference and draging a ILPanel from the toolbar to my form.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ILNumerics;
using ILNumerics.Drawing;
using ILNumerics.Drawing.Plotting;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void ilPanel1_Load_1(object sender, EventArgs e) {
var scene = new ILScene();
scene.Add(new ILSphere());
ilPanel1.Scene = scene;
}
}
}
It shows a sphere. But the sphere always is the full size of the window. Mouse rotation does not work either. What am I missing?
Instead of
scene.Add(new ILSphere());
you can add the sphere below the standard Camera in the scene:
scene.Camera.Add(new ILSphere());
This will give you the desired result. The camera creates its own coordinate system, positions objects within its subtree and provides all interactive options for them (rotation, zoom, pan etc.)
I'm using PRISM4 MVVM Pattern, and the views are loaded successfully and displayed on the appropriate regions when the application starts. When the application starts, the ViewModels are initialized automatically when the view is loaded. However, if I try to inject a new view on a new tab (new region), the ViewModel of the new view is not initialized. Here's the code for view injection:
IRegion region = regionManager.Regions["RegionNameGoesHere"];
var pane = new Views.ABCView() {Tag = id};
regionManager.Regions["RegionNameGoesHere"].Add(pane);
The code above opens a new tab and load the new view, but it doesn't initialize the ViewModel. Each tab of the control is a new region (there's a RegionAdapter for the tab control).
Here's the code behind the view:
using System.ComponentModel.Composition;
using System.Diagnostics.CodeAnalysis;
using System.Windows.Controls;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.Docking;
namespace Company.Application.Module.Assembly.Views
{
[Infrastructure.Behaviours.ViewExport("ABCView")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class ABCView : RadPane
{
public ABCView()
{
this.InitializeComponent();
}
/// <summary>
/// Sets the ViewModel.
/// </summary>
/// <remarks>
/// This set-only property is annotated with the <see cref="ImportAttribute"/> so it is injected by MEF with
/// the appropriate view model.
/// </remarks>
[Import]
[SuppressMessage("Microsoft.Design", "CA1044:PropertiesShouldNotBeWriteOnly", Justification = "Needs to be a property to be composed by MEF")]
ABCViewModel ViewModel
{
set
{
this.Decorator.DataContext = value;
//this.DataContext = value;
}
}
}
}
And here's the ViewModel with a few properties and events. I'm missing something in the code above to initialize the ViewModel below. Any suggestion is greatly appreciated.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel.Composition;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml;
using System.Xml.XPath;
using System.Windows.Data;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Prism.ViewModel;
namespace Company.Application.Module.Assembly.Views
{
[Export(typeof(ABCViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ABCViewModel : NotificationObject
{
private readonly IRegionManager regionManager;
[ImportingConstructor]
public ABCViewModel(IRegionManager regionManager)
{
// Event Aggregator
//this.eventAggregator = eventAggregator;
// Region Manager
this.regionManager = regionManager;
}
#region P R O P E R T I E S
#region E V E N T S
}
}
The problem is that you are creating the view yourself instead of having the CompositionContainer create it for you. The CompositionContainer doesn't know anything about objects you create yourself, so when you call new Views.ABCView(), the imports aren't magically satisfied.
With raw MEF, you would call CompositionContainer.GetExports() to get a view from the container. There is probably some infrastructure in Prism that wraps around this call, but I don't know much about Prism so I don't know exactly what that would be.
I'm writing an WPF application where I need to show a Webcam feed. I was able to do this easly with the AForge framework.But when I've changed from a computer to a another computer the same code doesn't work the same way.
In the first one the webcam feed works perfectly, but in the other one this does't occur, the feed has a lot of delay, and the application doesn't work properly.
Here is the code:
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap img = (Bitmap)eventArgs.Frame.Clone();
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, (SendOrPostCallback)delegate
{
IntPtr hBitmap = img.GetHbitmap();
System.Windows.Media.Imaging.BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
DeleteObject(hBitmap);
img.Dispose();
GC.Collect();
image1.Source = bitmapSource;
}, null);
}
What this code is really simple, it gets a new_frame from the webcam in a form of a Bitmap, and what I need to do is to convert it to a BitmapSource, so I can show in the image frame of the WPF. I think this conversion is the responsible of the mess that is happening, but I don't understand why it works in a computer and in the other doesn't.
The computer specs are almost the same, the processor is the same, as well the system memory.
My problem here is about performance, this code in one computer runs smoothly, and the webcam feed is presented as it should, when I port it to another PC this doesn't happen.
Here is working code based on this article.
(1) Download and install last AForge framework. (I have used version 2.2.4)
(2) Create WPF Application project.
(3) Add references to those AForge DLLs. (You can find them under C:\Program Files (x86)\AForge.NET\Framework\Release folder i.e.)
(4) Build your project. (I have used VS 2012)
(5) Add WPF Image control and name it "frameHolder".
So you have something like
<Window x:Class="WpfApplication1.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">
<Grid>
<Image HorizontalAlignment="Stretch" Name="frameHolder" VerticalAlignment="Stretch" Stretch="Fill"/>
</Grid>
</Window>
(6) Add C# code:
using AForge.Video;
using AForge.Video.DirectShow;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
/////
namespace WpfApplication1
{
public partial class MainWindow : Window
{
VideoCaptureDevice LocalWebCam;
public FilterInfoCollection LoaclWebCamsCollection;
void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
System.Drawing.Image img = (Bitmap)eventArgs.Frame.Clone();
MemoryStream ms = new MemoryStream();
img.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = ms;
bi.EndInit();
bi.Freeze();
Dispatcher.BeginInvoke(new ThreadStart(delegate
{
frameHolder.Source = bi;
}));
}
catch (Exception ex)
{
}
}
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
LoaclWebCamsCollection = new FilterInfoCollection(FilterCategory.VideoInputDevice);
LocalWebCam = new VideoCaptureDevice(LoaclWebCamsCollection[0].MonikerString);
LocalWebCam.NewFrame += new NewFrameEventHandler(Cam_NewFrame);
LocalWebCam.Start();
}
}
}
(7) Re-Build project and it works!
Note: We use first detected WebCam by default.
Make sure you have WebCam driver insalled and WebCam is working in general... :)
I know the original post is over 3 years old, but I just have been trying to figure out how to use this code. I found that the answer given by Dimi is nearly a fully functional code. However, I found that I have issues with memory leaking and the frame not being render reliably on some computers. The code worked perfectly on my beefier development computer (i7, 16GB RAM, Quadro Pro Grapthics card), but when I deployed the app on a computer with more limited resources (i5, 4GB RAM, Integrated Intel graphics), the frame disappears once in a while and the program would also crash after the system memory runs out. After searching the internet for a while, I think I finally patched together a working code based on all the feedback people had. I know that the other computer is capable of running frame capture from the webcam because I have a WinForm C# app that I wrote using AForge.NET and it has no issues rendering the frame reliably and with no memory leak. Unfortunately WPF doesn't handle graphics the same way as WinForm and we have to do this hack to get AForge.NET to work with it.
Basically, the code is the same as Dimi's except for the Cam_NewFrame method.
void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
BitmapImage bi;
using(var bitmap = (Bitmap)eventArgs.Frame.Clone())
{
bi = new BitmapImage();
bi.BeginInit();
MemoryStream ms = new MemoryStream();
bitmap.Save(ms, ImageFormat.Bmp);
bi.StreamSource = ms;
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.EndInit();
}
bi.Freeze();
Dispatcher.BeginInvoke(new ThreadStart(delegate { frameHolder.Source = bi; }));
}
catch (Exception ex)
{
//catch your error here
}
}
The changes that were made are the following:
Enclosing the bitmap handling with Using scope so that any unused memory is cleaned up right away after the end of scope.
Moving the bi.BeginInit() before dealing with the memory stream so that the bitmap is ready for the memomory dump right away.
Changing the CacheOption to OnLoad so that all the image memory gets dump right at the loading. Otherwise, it uses BitmapCacheOption.Default which could allow the image to hold on to the memory even when bi.Freeze() is issued. This caused the frame to not be rendered even with the Dispatcher.BeginInvoke is called to render the image.
So far it's been working well but if anyone else spot other issues please make a comment so we know how to fix it.
In my WPF MediaKit, I have a control called VideoCaptureElement that will render a webcam to WPF. You can also get access to the samples by hooking into the new image event and setting the EnableSampleGrabbing on the element.
Maybe the webcam on the other computer is broken/faulty? Or has one of the webcams that doesnt support the DirectShow api, which i think AForge builds on.
.Net contains a nice control called DocumentViewer. it also offers a subcontrol for finding text in the loaded document (that's at least what it is supposed to do).
When inserting FixedPage's objects as document source for the DocumentViewer, the find-functionality just does not find anything. Not even single letters. I haven't tried FlowDocument's yet,
as the documentation for DocumentViewer is not that useful and the resources on the net are not actually existing, I now want to ask the stackoverflow community:
What does it need to get the Find-Function of the WPF DocumentViewer working with FixedPage documents?
[btw, I don't use custom ControlTemplates for DocumentViewer]
I had this same problem with FixedDocuments. If you convert your FixedDocument to an XPS document then it works fine.
Example of creating an XPS Document in memory from a FixedDocument then displaying in a DocumentViewer.
// Add to xaml: <DocumentViewer x:Name="documentViewer" />
// Add project references to "ReachFramework" and "System.Printing"
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.IO;
using System.IO.Packaging;
using System.Windows.Xps.Packaging;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Set up demo FixedDocument containing text to be searched
var fixedDocument = new FixedDocument();
var pageContent = new PageContent();
var fixedPage = new FixedPage();
fixedPage.Children.Add(new TextBlock() { Text = "Demo document text." });
pageContent.Child = fixedPage;
fixedDocument.Pages.Add(pageContent);
// Set up fresh XpsDocument
var stream = new MemoryStream();
var uri = new Uri("pack://document.xps");
var package = Package.Open(stream, FileMode.Create, FileAccess.ReadWrite);
PackageStore.AddPackage(uri, package);
var xpsDoc = new XpsDocument(package, CompressionOption.NotCompressed, uri.AbsoluteUri);
// Write FixedDocument to the XpsDocument
var docWriter = XpsDocument.CreateXpsDocumentWriter(xpsDoc);
docWriter.Write(fixedDocument);
// Display XpsDocument in DocumentViewer
documentViewer.Document = xpsDoc.GetFixedDocumentSequence();
}
}
}
I had trouble with searching text in richtextbox, it was too slow. What I did was crunch the xaml every time I wanted to search. I improved several orders of magnitude.
It's a big workaround based in a part of the Chris Anderson's book.
Cheers