|
Hi,
this problem is not specific to WPF. There generally are two remedies:
1. only load what is really necessary; having controls that support a "virtual" mode makes that easier.
2. compute "thumbnails" once, and store them on disk, together with the actual images. Don't worry about disk space, they could well be 100 times smaller than the originals.
Luc Pattyn [Forum Guidelines] [My Articles]
- before you ask a question here, search CodeProject, then Google
- the quality and detail of your question reflects on the effectiveness of the help you are likely to get
- use the code block button (PRE tags) to preserve formatting when showing multi-line code snippets
|
|
|
|
|
I'm using controls, that support "virtual" mode, and i think it work on scrolling, but i interest in faster startup. I don't know why it starts so long, and i assume that all the images are cached on load. Maybe i'm wrong, but i don't know another reason. That's why i need help. If it matter's, i can show code.
|
|
|
|
|
Hi,
improving the performance is similar to debugging, so gather the facts, analyze, formulate an hypothesis, verify, fix, and iterate.
These are the first steps I would take:
- install logging code, basically a "public static void log(string)" method that saves a string to a log file;
- set up a StopWatch, so each log message automatically gets prefixed with the elapsed time with millisecond resolution
- sprinkle log statements in the relevant parts of the app.
- now have a trial run: startup, stop, look at the log file; any time gap exceeding say 100 msec needs either more log statements, and if that is not possible, is a hotspot in need of fixing. It might be a Thread.Sleep() you forgot to remove, a first database access (move to another thread?), a first network access, etc.
Luc Pattyn [Forum Guidelines] [My Articles]
- before you ask a question here, search CodeProject, then Google
- the quality and detail of your question reflects on the effectiveness of the help you are likely to get
- use the code block button (PRE tags) to preserve formatting when showing multi-line code snippets
|
|
|
|
|
S.a.n.4.e.s wrote: i assume that all the images are cached on load
not sure what you mean.
S.a.n.4.e.s wrote: If it matter's, i can show code
it might be useful, *after* you tried to localize and fix the slow parts.
Luc Pattyn [Forum Guidelines] [My Articles]
- before you ask a question here, search CodeProject, then Google
- the quality and detail of your question reflects on the effectiveness of the help you are likely to get
- use the code block button (PRE tags) to preserve formatting when showing multi-line code snippets
|
|
|
|
|
<blockquote class="FQ"><div class="FQA">Luc Pattyn wrote:</div> S.a.n.4.e.s wrote:
i assume that all the images are cached on load
not sure what you mean.</blockquote>
I mean, that all the collection of images, binded to ListView, are loading on startup. I use a single thread, don't use network or database, i simple get *.jpg files from some directory on one of my disks.
There's my code.
XAML:
<pre>
<usercontrol.resources>
<objectdataprovider x:name="PhotosODP" x:key="MyPhotos" objecttype="{x:Type l:PhotoList}" xmlns:x="#unknown" />
<l:uritoimageconverter x:key="LocalUriToImageConverter" xmlns:x="#unknown" xmlns:l="#unknown" />
<DataTemplate DataType="{x:Type l:Photo}">
<Grid VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
<Border Background="#FF562100" Padding="4" BorderThickness="1">
<StackPanel Width="{Binding ElementName=Zoomer, Path=Value}" Margin="5" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
<Image Source="{Binding Source, Converter={StaticResource LocalUriToImageConverter}}" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"/>
<Label Foreground="White" Content="{Binding FileName}" />
</StackPanel>
</Border>
</Grid>
</DataTemplate>
</usercontrol.resources>
</pre>
And C# class, that makes a collection:
<pre>
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Media.Imaging;
namespace Components
{
public class Photo
{
public Photo(string path)
{
_source = path;
_name = path.Substring(path.LastIndexOf("\\") + 1);
}
public override string ToString()
{
return Source;
}
private string _source;
public string Source { get { return _source; } }
//my
private string _name;
public string FileName { get { return _name; } }
//
}
public class PhotoList : ObservableCollection<photo>
{
public PhotoList() { }
public PhotoList(string path) : this(new DirectoryInfo(path)) { }
public PhotoList(DirectoryInfo directory)
{
_directory = directory;
Update();
}
public string Path
{
set
{
_directory = new DirectoryInfo(value);
Update();
}
get { return _directory.FullName; }
}
public DirectoryInfo Directory
{
set
{
_directory = value;
Update();
}
get { return _directory; }
}
private void Update()
{
foreach (FileInfo f in _directory.GetFiles("*.jpg"))
{
Add(new Photo(f.FullName));
}
}
DirectoryInfo _directory;
}
}
</photo></pre>
And an event of an app, on which load of images starts:
<pre>
private void UserControl_Initialized(object sender, EventArgs e)
{
photos = (PhotoList)(this.Resources["MyPhotos"] as ObjectDataProvider).Data;
photos.Path = path;
}
</pre>
modified on Saturday, March 14, 2009 6:57 AM
|
|
|
|
|
Hi,
I am using InkCanvas control for signature. Can anyone tell me how to store these signatures in sql server DB?
Vsaratkar
|
|
|
|
|
Save the strokes to a memory stream
var memoryStream = new System.IO.MemoryStream();
inkCanvas.Strokes.Save(memoryStream);
to compress the data
then store the data of the memory stream in your database as an appropriate binary type.
to load the data to an InkCanvans from a memory stream
inkCanvas1.Strokes = new StrokeCollection(memoryStream);
memoryStream = 0
Eslam Afifi
|
|
|
|
|
|
Glad to help
Eslam Afifi
|
|
|
|
|
I see how to store the strokes DB. We've been successful at this in storing signatures from a tablet application. I now want to be able to present our signatures via a web report. I want to be able to convert my strokes directly to a png or bitmap and display using SS Reporting Services image control. So, I need to convert the strokes collection, stored in the database, to to bitmap byte[], as we're unable to use the inkcavas control in SSRS. Does anyone know how to do this?
-Andy
|
|
|
|
|
Adventures into Ink API using WPF[^] does that. But it outputs only the visible parts of the ink. You may want to ensure that the InkCanvas or InkPresenter is big enough to contain all the ink in it.
The StrokeCollection has a method Draw[^] that draws on a DrawingContext, maybe you want to investigate that.
By the way, you should start a new thread instead of replying to an old one to increase the probability that someone see your question and someone may have a better solution.
Eslam Afifi
|
|
|
|
|
Hello.
Has anyone come across a nice, sturdy Tweening library for WPF? Coming from Flash I have been spoiled by Tweener, TweenMax, GTween etc and am in shock that MS has not provided something similar for WPF when us designers consider it an essential.
Cheers, E.
|
|
|
|
|
This Silverlight version[^] looks promising - a WPF version would be extremely simple to achieve.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys
|
|
|
|
|
Chers for that, I'll give it a whirl. I found Bling too which is mighty fun.
|
|
|
|
|
Hi
I discovered that Blender can export to the .obj format which is supported in Expression Blend, so I'll be using Blender as my 3D modeling application.
The problem I'm facing though, is loading these models onto a ViewPort whenever the user wishes to do so, and not whenever the application loads e.g. I want to create a drop down menu which displays all my models, and as soon as the user clicks on a menu item ("chair" for instance), an already created model of a chair must be loaded and displayed. Is this possible, and how?
Code samples would be helpful
Thanks in advance
|
|
|
|
|
I've used the XAML Exporter for Blender[^] instead. Basically, you export your model out as XAML, which you can then bind in using XamlReader.Load.
The first step I'd take would be to define an ObservableCollection which was populated by reading in a list of items from a particular directory that end in xaml. Then, I'd bind this to the menu which would then trigger the load.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys
|
|
|
|
|
I'm using datagrid from WPF Toolkit. And I have my owen style for column header. Here is code:
<Style x:Key="ColumnHeaderStyle" TargetType="{x:Type dg:DataGridColumnHeader}">
<Setter Property="Background" Value="{StaticResource DataGrid_Style0_Header}" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="BorderBrush" Value="#FFFFCB02" />
<Setter Property="BorderThickness" Value="0,0,1,1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type dg:DataGridColumnHeader}">
<Border BorderBrush="{TemplateBinding dg:DataGridColumnHeader.BorderBrush}" BorderThickness="{TemplateBinding dg:DataGridColumnHeader.BorderThickness}">
<Grid Name="grContentHeader" Height="20" Background="{TemplateBinding dg:DataGridColumnHeader.Background}">
<ContentPresenter Content="{TemplateBinding dg:DataGridColumnHeader.Content}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" Cursor="Hand" Margin="2,0,2,0"/>
<Path Name="UpArrow" Fill="Black" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,3,0" Visibility="Hidden">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="6,0"/>
<LineSegment Point="3,5"/>
<LineSegment Point="0,0"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path Name="DownArrow" Fill="Black" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,3,0" Visibility="Hidden">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0,5">
<LineSegment Point="6,5"/>
<LineSegment Point="3,0"/>
<LineSegment Point="0,5"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="SortDirection" Value="Ascending">
<Setter TargetName="DownArrow" Property="Visibility" Value="Visible"/>
<Setter TargetName="UpArrow" Property="Visibility" Value="Hidden"/>
<Setter TargetName="grContentHeader" Property="Background" Value="{StaticResource DataGrid_Header_Alt0}"/>
</Trigger>
<Trigger Property="SortDirection" Value="Descending">
<Setter TargetName="DownArrow" Property="Visibility" Value="Hidden"/>
<Setter TargetName="UpArrow" Property="Visibility" Value="Visible"/>
<Setter TargetName="grContentHeader" Property="Background" Value="{StaticResource DataGrid_Header_Alt0}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Problem is, that i can't resize column.
CanUserResize="True" for column and CanUserResizeColumns="True" for datagrid don't work.
Please help
<div class="ForumMod">modified on Thursday, March 12, 2009 5:23 AM</div>
|
|
|
|
|
Did you see this Thumb controls[^] ? You don't seem to have the resizing Thumb in your Template.
|
|
|
|
|
You right. I must look for some tutorial, how to use Thumb control and implement into my code. THX lot
|
|
|
|
|
The article I mentioned has it implemented.
|
|
|
|
|
Again... THX LOT! It works.
modified on Thursday, March 12, 2009 6:14 AM
|
|
|
|
|
Hello,
i´m trying to write a WPF User Control that looks like a matrix of LEDs.
I´ve created a RenderTargetBitmap over a DrawingVisual that looks like a matrix of quadratic dots.
The problem is that, when using the control, the dots are not displayed quadratic. The dots are displayed rectangular instead and very small.
I´ve also saved the created matrix bitmap in a bmp file. The matrix bitmap is correctly displayed if it is opened with a standard program.
How can i change rendering, so that the pixel of the matrix bitmap are displayed correctly?
In the past i´ve created such a matrix bitmap with MFC and BitBlt, ther was no such blur, if the bitmap was displayed by a control.
I used the following code in my control:
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.IO;
namespace TestWpf
{
public partial class MyControl : UserControl
{
private const double INCH_PER_UNIT = 1.0 / 96.0;
private const int BMP_DPI = 96;
private const double PIXEL_RAD = 1;
private const double PIXEL_SPACE = 1;
private static readonly Brush PIXEL_OFF_BRUSH = new SolidColorBrush(Color.FromRgb(150, 150, 150));
private static readonly Brush PIXEL_BACKGND_BRUSH = new SolidColorBrush(Colors.Black);
RenderTargetBitmap _pixelOffBmp;
RenderTargetBitmap _matrixBmp;
public MyControl()
{
InitializeComponent();
_pixelOffBmp = CreatePixelBmp(PIXEL_OFF_BRUSH);
_matrixBmp = CreateMatrixBmp();
SaveBmp(_matrixBmp);
}
protected override void OnRender(DrawingContext drawingContext)
{
drawingContext.DrawImage(_matrixBmp, new Rect(0, 0, _matrixBmp.Width, _matrixBmp.Height));
}
RenderTargetBitmap CreatePixelBmp(Brush pixBrush)
{
double unitWidth, unitHeight;
unitWidth = 2 * PIXEL_RAD;
unitHeight = unitWidth;
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext dc = drawingVisual.RenderOpen())
{
dc.DrawRectangle(pixBrush, null, new Rect(0, 0, unitWidth, unitHeight));
}
int pixelWidth, pixelHeight;
pixelWidth = (int)(BMP_DPI * unitWidth * INCH_PER_UNIT);
pixelHeight = (int)(BMP_DPI * unitHeight * INCH_PER_UNIT);
RenderTargetBitmap bmp = new RenderTargetBitmap(pixelWidth, pixelHeight, BMP_DPI, BMP_DPI, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
bmp.Freeze();
return bmp;
}
RenderTargetBitmap CreateMatrixBmp()
{
int xMatrixPixel = 20 * 6;
int yMatrixPixel = 2 * 8;
double xUnitsMatrixBmp = xMatrixPixel * (2 * PIXEL_RAD + PIXEL_SPACE) + PIXEL_SPACE;
double yUnitsMatrixBmp = yMatrixPixel * (2 * PIXEL_RAD + PIXEL_SPACE) +PIXEL_SPACE;
int pixelWidthMatrixBmp = (int)(BMP_DPI * xUnitsMatrixBmp * INCH_PER_UNIT);
int pixelHeightMatrixBmp = (int)(BMP_DPI * yUnitsMatrixBmp * INCH_PER_UNIT);
this.Width = xUnitsMatrixBmp + BorderThickness.Left + BorderThickness.Right;
this.Height = yUnitsMatrixBmp + BorderThickness.Top + BorderThickness.Bottom;
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext dc = drawingVisual.RenderOpen())
{
dc.DrawRectangle(PIXEL_BACKGND_BRUSH, null, new Rect(0, 0, xUnitsMatrixBmp, yUnitsMatrixBmp));
double xOffset = 0;
double yOffset = PIXEL_SPACE;
for (int y = 0; y < yMatrixPixel; y++)
{
xOffset = PIXEL_SPACE;
for (int x = 0; x < xMatrixPixel; x++)
{
dc.DrawImage(_pixelOffBmp, new Rect(xOffset, yOffset, _pixelOffBmp.Width, _pixelOffBmp.Height));
xOffset += _pixelOffBmp.Width + PIXEL_SPACE;
}
yOffset += _pixelOffBmp.Height + PIXEL_SPACE;
}
}
RenderTargetBitmap bmp = new RenderTargetBitmap(pixelWidthMatrixBmp, pixelHeightMatrixBmp, BMP_DPI, BMP_DPI, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
bmp.Freeze();
return bmp;
}
void SaveBmp(BitmapSource bmpSource)
{
BmpBitmapEncoder bmp = new BmpBitmapEncoder();
bmp.Frames.Add(BitmapFrame.Create(bmpSource));
using (Stream stm = File.Create("foo.bmp"))
{
bmp.Save(stm);
}
}
}
}
Thanks,
Andy
|
|
|
|
|
This problem occurs due to WPFs resolution independence and most noticible with images like your example. An overview is at http://msdn.microsoft.com/en-us/library/aa970908.aspx and if you search with terms like "wpf pixel snapping" you'll find a lot of blog posts about the subject.
In the end I got your example working with a rather crude method.
public MyControl()
{
InitializeComponent();
RenderOptions.SetBitmapScalingMode(this,BitmapScalingMode.NearestNeighbor);
_pixelOffBmp = CreatePixelBmp(PIXEL_OFF_BRUSH);
_matrixBmp = CreateMatrixBmp();
SaveBmp(_matrixBmp);
LayoutUpdated += (s, e) => InvalidateVisual();
}
protected override void OnRender(DrawingContext drawingContext)
{
var pos = this.PointFromScreen(this.PointToScreen(new Point(0, 0)));
double x = pos.X - Math.Floor(pos.X);
double y = pos.Y - Math.Floor(pos.Y);
drawingContext.DrawImage(_matrixBmp, new Rect(1-x,1-y, _matrixBmp.Width, _matrixBmp.Height));
}
If you just want a repeating pattern ImageBrush might be what your after.
You may want to rethink your approach if you want to get the best out of WPF. For example each LED could be an individual control laid out inside a UniformGrid and have its appearance change using data binding. This sudoku tutorial might give you some ideas although I don't know what your control is going to display, I was thinking along the lines of a graph/audio spectrum.
|
|
|
|
|
Thanks a lot for your anwser, it helps a lot.
The matrix bitmap is now correctly displayed.
To update the LEDs, i use a second bitmap, the _contentBmp, with the same size as the matrix bmp.
Now the matrix bmp is copied into the content bmp and for each LED whch is on, a bmp that represent the on status is copied into the content bmp.
The content bmp is now used in the OnRender().
A timer in the main window sets and resets the LEDs every 200 milli seconds:
MyCtrl.PixelEnabled = !MyCtrl.PixelEnabled
RenderTargetBitmap _pixelOffBmp;
RenderTargetBitmap _pixelGreenBmp;
RenderTargetBitmap _matrixBmp;
RenderTargetBitmap _contentBmp;
int _xMatrixPixel;
int _yMatrixPixel;
double _xUnitsMatrixBmp;
double _yUnitsMatrixBmp;
private bool _pixelEnabled = false;
public bool PixelEnabled
{
get { return _pixelEnabled; }
set
{
_pixelEnabled = value;
UpdateDisplay();
}
}
RenderTargetBitmap CreateMatrixBmp()
{
......
RenderTargetBitmap bmp = new RenderTargetBitmap(pixelWidthMatrixBmp, pixelHeightMatrixBmp, BMP_DPI, BMP_DPI, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
bmp.Freeze();
_contentBmp = new RenderTargetBitmap(pixelWidthMatrixBmp, pixelHeightMatrixBmp, BMP_DPI, BMP_DPI, PixelFormats.Pbgra32);
return bmp;
}
void UpdateDisplay()
{
RenderTargetBitmap pixelBmp;
if (!PixelEnabled) pixelBmp = _pixelOffBmp;
else pixelBmp = _pixelGreenBmp;
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext dc = drawingVisual.RenderOpen())
{
dc.DrawImage(_matrixBmp, new Rect(0, 0, _xUnitsMatrixBmp, _yUnitsMatrixBmp));
double xOffset = 0;
double yOffset = PIXEL_SPACE;
for (int y = 0; y < _yMatrixPixel; y++)
{
xOffset = PIXEL_SPACE;
for (int x = 0; x < _xMatrixPixel; x++)
{
if (x % 5 == 0)
dc.DrawImage(pixelBmp, new Rect(xOffset, yOffset, pixelBmp.Width, pixelBmp.Height));
xOffset += pixelBmp.Width + PIXEL_SPACE;
}
yOffset += pixelBmp.Height + PIXEL_SPACE;
}
}
_contentBmp.Render(drawingVisual);
}
protected override void OnRender(DrawingContext drawingContext)
{
var pos = this.PointFromScreen(this.PointToScreen(new Point(0, 0)));
double x = pos.X - Math.Floor(pos.X);
double y = pos.Y - Math.Floor(pos.Y);
drawingContext.DrawImage(_contentBmp, new Rect(1-x, 1-y, _contentBmp.Width, _contentBmp.Height));
}
Now the problem is that the CPU usage is about 50%!
The cause that the LayoutUpdated Event calls InvalidateVisual().
But without calling InvalidateVisual() the Bitmap is not correctly displayed if the size of the main window is changed by user.
The Sudoku sample is very interesting and i will study it exactly by the next opportunity.
But i´m skeptic about the performance.
Earlier than the approach with bitmaps, i´ve created a LED matrix with Shapes and that takes a lot of performance.
I like to create the LED matrix for simulating a LED Display, which can display text and graphic, the text can flash or it can by marquee text etc.
The size of the display can be 240 x 48 pixel, so i have 11520 controls.
|
|
|
|
|
That is probably too many controls.
I just tried a few other methods for the offset that I thought might work but they produced artifacts.
Overlaying an ImageBrush of the gridlines on to normal content might be good enough or you could try writing a custom pixel shader. The one below is based on PixelateEffect but puts gaps inbetween. Shazzam is quite handy.
float HorizontalPixelCounts : register(C0);
float VerticalPixelCounts : register(C1);
sampler2D implicitInputSampler : register(S0);
float4 main(float2 uv : TEXCOORD) : COLOR
{
float2 brickCounts = { HorizontalPixelCounts, VerticalPixelCounts };
float2 brickSize = 1.0 / brickCounts;
float2 brickNum = floor(uv / brickSize);
float2 centerOfBrick = brickNum * brickSize + brickSize / 2;
float2 edge = uv - (brickNum * brickSize);
if(edge.x < 0.01 || edge.y < 0.01)
{
return float4(0,0,0,0);
}
return tex2D(implicitInputSampler, centerOfBrick);
}
|
|
|
|
|