Creating WriteableBitmap form chart issue - c#

I have a problem when trying to create writeable bitmap form Silverlight toolkit Graph.
When using textBlock, everything is fine, but after trying to use Chart, generated bitmap is empty :( .
var data = new List<Point>(100);
for (int i = 0; i < 100; i++)
{
data.Add(new Point(i, Math.Sin(i * Math.PI / 50)));
}
Chart chart_ = new Chart()
{
Name = "Chart",
Width = 512,
Height = 512
};
LineSeries line = new LineSeries()
{
Name = "Line",
Title = "test",
IndependentValuePath = "X",
DependentValuePath = "Y",
ItemsSource = data
};
chart_.Series.Add(line);
This code creates chart with sinusoid in it. Then Im trying to create bitmap from it.
LayoutRoot.Children.Add(chart_); // I tried to add chart_ to visual tree, It doesn't help
//creates bitmap
ScaleTransform t = new ScaleTransform() { ScaleX = 1.0, ScaleY = 1.0 };
//bitmap = new WriteableBitmap(chart_, t); Tried it also with this way
bitmap = new WriteableBitmap(512, 512);
bitmap.Render(chart_, t);
texture = new Texture2D(GraphicsDeviceManager.Current.GraphicsDevice, bitmap.PixelWidth, bitmap.PixelHeight, false, SurfaceFormat.Color);
bitmap.CopyTo(texture);
All this code creates Empty Bitmap.But when I use TextBlock or some primitives like Ellipse, everything works. Im sure, that code generating chart is fine, cause chart is generated fine in Silverlight control.
EDIT:
I tried to create bitmap this way, but it dont help.
chart_.InvalidateMeasure();
bitmap = new WriteableBitmap(512, 512);
bitmap.Render(chart_, null);
bitmap.Invalidate();
EDIT 2:
I don't want graph to be in visual tree. I just need generate image of it an than use it in XNA part of my application.

Just a couple of small changes, but I suspect the big change is manually adding a reference to System.Windows.Controls after using NuGet to add the Charting package.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.DataVisualization.Charting;
using System.Windows.Media.Imaging;
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
Chart chart_;
public MainPage()
{
InitializeComponent();
var data = new List<Point>(100);
for (int i = 0; i < 100; i++)
{
data.Add(new Point(i, Math.Sin(i * Math.PI / 50)));
}
chart_ = new Chart()
{
Name = "Chart",
Width = 512,
Height = 512
};
LineSeries line = new LineSeries()
{
Name = "Line",
Title = "test",
IndependentValuePath = "X",
DependentValuePath = "Y",
ItemsSource = data
};
chart_.Series.Add(line);
LayoutRoot.Children.Add(chart_); // I tried to add chart_ to visual tree, It doesn't help
}
private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
//creates bitmap
WriteableBitmap bitmap;
ScaleTransform t = new ScaleTransform() { ScaleX = 1.0, ScaleY = 1.0 };
//bitmap = new WriteableBitmap(chart_, t); Tried it also with this way
bitmap = new WriteableBitmap(512, 512);
bitmap.Render(chart_, t);
//texture = new Texture2D(GraphicsDeviceManager.Current.GraphicsDevice, bitmap.PixelWidth, bitmap.PixelHeight, false, SurfaceFormat.Color);
//bitmap.CopyTo(texture);
image1.Source = bitmap;
}
}
}
And
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
<Grid x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded">
<Image Height="150" HorizontalAlignment="Left" Margin="97,109,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="200" />
</Grid>
</UserControl>
That should get you going...
Don't forget to delete all of the attempted workarounds - I don't think any of them are necessary. The only code I did not use from your example had to do with the textures - I didn't know what to do with that and it wasn't the problem you were having anyways...
David

I believe that by the time you are creating WriteableBitmap object & calling Render method, Chart has not be rendered yet. You can check this by moving these lines of code to some other event like Button_Click etc. Have a look at below codes as it is creating the WriteableBitmap and then passes it to image control as source....
XAML Code.....
<UserControl x:Class="TryBitmap.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="35"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Height="25" Width="100" Content="Capture" Click="Button_Click"/>
<Grid x:Name="grdGraphs" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image x:Name="img" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
Code Behind....
public partial class MainPage : UserControl
{
private Chart chart_;
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var data = new List<Point>(100);
for (int i = 0; i < 100; i++)
{
data.Add(new Point(i, Math.Sin(i * Math.PI / 50)));
}
chart_ = new Chart()
{
Name = "Chart",
Width = 512,
Height = 512
};
LineSeries line = new LineSeries()
{
Name = "Line",
Title = "test",
IndependentValuePath = "X",
DependentValuePath = "Y",
ItemsSource = data
};
chart_.Series.Add(line);
chart_.SetValue(Grid.ColumnProperty, 0);
grdGraphs.Children.Add(chart_);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var bitmap = new WriteableBitmap((int)(chart_.RenderSize.Width), (int)(chart_.RenderSize.Height));
bitmap.Render(chart_, new MatrixTransform());
bitmap.Invalidate();
img.Source = bitmap;
}
}

I'm afraid this is only going to be half an answer. I can solve your immediate problem but I'm afraid you'll just end up with another one I haven't managed to solve.
Creating the bitmap after a call to Dispatcher.BeginInvoke should ensure that your bitmap isn't completely blank, i.e.:
// do stuff with chart_ ...
Dispatcher.BeginInvoke(() =>
{
bitmap = new WriteableBitmap(512, 512);
bitmap.Render(chart_, null);
bitmap.Invalidate();
// At this point, the bitmap shouldn't be blank.
});
However, the results of this likely to be less than satisfactory. I ran your code and I found that the LineSeries was missing from the chart image, although the rest of the chart was there. This remained true even after I set all Durations of the various animations in the ControlTemplate for the LineSeries to 0 and additionally set the following properties on the chart:
chart_.AnimationSequence = AnimationSequence.Simultaneous;
chart_.TransitionDuration = new TimeSpan(0);
I tried wrapping the WriteableBitmap operations in further calls to Dispatcher.BeginInvoke(), and after doing this the data points started to appear more clearly. However, I can't believe that an approach like this is the right solution to the problem.

Related

WPF: Connecting rectangles on canvas dynamically with path between

This is my first time posting, so be easy on me...
There are definitely posts that show how to connect lines to blocks, but this one is slightly different. The grids are placed on the canvas dynamically. I want a line to connect the grid from where the button is pressed to the new grid that's placed on the canvas. However the below code doesn't work. I've struggled with this one for a very long time.
Solely by accident I discovered a Messagebox thrown in the button event handler will allow it to work. I figured this was from threads running at different times, but after messing with task.delay/thread.sleep/async/await I can't find the solution.
I'm using custom classes because this is a stripped down version of the larger program, I wanted to have similar functionality in my example to reflect possible errors but leave out the unnecessary pieces.
I'm using this as a last resort, thank you in advance for any help you can provide. First the CS code
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
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
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Grid1 g = myCanvas.CreateGrid();
ContentControl1 cc = myCanvas.CreateCC();
Button1 b = myCanvas.CreateButton1();
Grid1.SetColumn(cc, 0);
Grid1.SetRow(cc, 0);
Grid1.SetColumn(b, 1);
Grid1.SetRow(b, 1);
g.Children.Add(cc);
g.Children.Add(b);
Canvas1.SetLeft(g, 500);
Canvas1.SetTop(g, 5);
myCanvas.Children.Add(g);
}
}
public class Button1 : Button
{
protected override void OnClick()
{
Grid1 old_g = (Grid1)VisualTreeHelper.GetParent(this as DependencyObject);
Canvas1 cnv = (Canvas1)VisualTreeHelper.GetParent(old_g as DependencyObject);
Grid1 g = cnv.CreateGrid();
ContentControl1 cc = cnv.CreateCC();
Button1 b = cnv.CreateButton1();
Grid1.SetColumn(cc, 0);
Grid1.SetRow(cc, 0);
Grid1.SetColumn(b, 1);
Grid1.SetRow(b, 1);
g.Children.Add(cc);
g.Children.Add(b);
Canvas1.SetLeft(g, 500);
Canvas1.SetTop(g, cnv.Children.Count * 120);
cnv.Children.Add(g);
cnv.ConnectGrids(old_g, g);
}
}
public class Canvas1 : Canvas
{
public Grid1 CreateGrid()
{
Grid1 g = new Grid1() { Width = 100, Height = 20, Background = Brushes.White };
g.HorizontalAlignment = HorizontalAlignment.Center;
g.VerticalAlignment = VerticalAlignment.Center;
g.ShowGridLines = false;
ColumnDefinition colDef1 = new ColumnDefinition();
ColumnDefinition colDef2 = new ColumnDefinition() { Width = new GridLength(20) };
g.ColumnDefinitions.Add(colDef1);
g.ColumnDefinitions.Add(colDef2);
RowDefinition rowDef1 = new RowDefinition();
g.RowDefinitions.Add(rowDef1);
return g;
}
public ContentControl1 CreateCC()
{
ContentControl1 cc = new ContentControl1()
{
VerticalContentAlignment = VerticalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Stretch,
BorderBrush = Brushes.BlueViolet,
};
return cc;
}
public Button1 CreateButton1()
{
Button1 b = new Button1()
{
VerticalContentAlignment = VerticalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Stretch,
BorderBrush = Brushes.Red
};
return b;
}
public void ConnectGrids(Grid1 g1, Grid1 g2)
{
Canvas1 cnv = (Canvas1)VisualTreeHelper.GetParent(g1 as DependencyObject);
Transform transform1 = (Transform)g1.TransformToVisual(cnv as Visual);
Transform transform2 = (Transform)g2.TransformToVisual(cnv as Visual);
Point StartPoint1 = transform1.Transform(new Point(g1.Width, g1.Height / 2.0));
Point EndPoint1 = transform2.Transform(new Point(g2.Width, g2.Height / 2.0));
var lineGeometry = new LineGeometry()
{
StartPoint = StartPoint1,
EndPoint = EndPoint1
};
var path = new Path()
{
Data = lineGeometry,
Stroke = new SolidColorBrush(Colors.Black),
};
cnv.Children.Add(path);
}
}
public class ContentControl1 : ContentControl
{
}
public class Grid1 : Grid
{
}
}
then the xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local ="clr-namespace:WpfApplication1"
Title="MainWindow" Height="1000" Width="1000">
<DockPanel>
<Button DockPanel.Dock="Top" Width="100" Height="20" Content="Start" Click="Button_Click"/>
<ScrollViewer HorizontalScrollBarVisibility="Visible" Width="901" x:Name="_scrollViewer" Margin="0,5,0,25">
<local:Canvas1 Background="Gray" Height="1000" Width="1000" x:Name="myCanvas"/>
</ScrollViewer>
</DockPanel>
</Window>
How can I successfully connect the grid with the path?
I love that I solved this/hate that I have to answer my own dumb question...
Sooo simple. UpdateLayout(). The objects don't change location until it has been rendered, so the line was going to its old location.

Server-side rendering of WPF UserControl

I am writing a server side console app in C#/.Net 4.5 that gets some data and creates static chart images that are saved to be displayed by a web server.
I am mostly using the method described here:
http://lordzoltan.blogspot.com/2010/09/using-wpf-to-render-bitmaps.html
However, I added a mainContainer.UpdateLayout(); after the Arrange() so that the databindings would update and be visible in the rendered image, as well as a Measure() before it for good... ah, I'm not gonna go there.
Here is the method that does the rendering:
void RenderAndSave(UIElement target, string filename, int width, int height)
{
var mainContainer = new Grid
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
mainContainer.Children.Add(target);
mainContainer.Measure(new Size(width, height));
mainContainer.Arrange(new Rect(0, 0, width, height));
mainContainer.UpdateLayout();
var encoder = new PngBitmapEncoder();
var render = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
render.Render(mainContainer);
encoder.Frames.Add(BitmapFrame.Create(render));
using (var s = File.Open(filename, FileMode.Create))
{
encoder.Save(s);
}
}
The target parameter to the method will be an instance of a WPF/XAML UserControl I made - fairly simple at this point, just a grid with some text databinding to a ViewModel object that I assigned to the DataContext.
The saved image on disk looks good EXCEPT for the OxyPlot Plot object - it is entirely white.
Now, when I am in the designer in Visual Studio 2013, I can see it. I have added a design-time DataContext which is the same object that I use at runtime (this is a spike I am doing - the viewmodel is not in its final form yet, just having a bunch of default data while I work out the kinks). In the designer I see the chart as OxyPlot paints it.
Is there anything special I need to do in order to get my rendering to also contain this OxyPlot chart? It is more or less the point of the exercise so it would be awesome to actually get it to show up!
Thanks in advance for any insights and suggestions!
If you're correctly binding data at runtime as well, then it should work.
[STAThread]
static void Main(string[] args)
{
string filename = "wpfimg.png";
RenderAndSave(new UserControl1(), filename, 300, 300);
PictureBox pb = new PictureBox();
pb.Width = 350;
pb.Height = 350;
pb.Image = System.Drawing.Image.FromFile(filename);
Form f = new Form();
f.Width = 375;
f.Height = 375;
f.Controls.Add(pb);
f.ShowDialog();
}
XAML:
<UserControl x:Class="WpfApp92.UserControl1"
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"
xmlns:oxy="http://oxyplot.org/wpf"
xmlns:local="clr-namespace:WpfApp92"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<oxy:PlotView Model="{Binding Model}"/>
</Grid>
</UserControl>
CS:
public partial class UserControl1 : UserControl
{
public PlotModel Model { get; set; }
public UserControl1()
{
InitializeComponent();
Model = new PlotModel();
Model.LegendBorderThickness = 0;
Model.LegendOrientation = LegendOrientation.Horizontal;
Model.LegendPlacement = LegendPlacement.Outside;
Model.LegendPosition = LegendPosition.BottomCenter;
Model.Title = "Simple model";
var categoryAxis1 = new CategoryAxis();
categoryAxis1.MinorStep = 1;
categoryAxis1.ActualLabels.Add("Category A");
categoryAxis1.ActualLabels.Add("Category B");
categoryAxis1.ActualLabels.Add("Category C");
categoryAxis1.ActualLabels.Add("Category D");
Model.Axes.Add(categoryAxis1);
var linearAxis1 = new LinearAxis();
linearAxis1.AbsoluteMinimum = 0;
linearAxis1.MaximumPadding = 0.06;
linearAxis1.MinimumPadding = 0;
Model.Axes.Add(linearAxis1);
var columnSeries1 = new ColumnSeries();
columnSeries1.StrokeThickness = 1;
columnSeries1.Title = "Series 1";
columnSeries1.Items.Add(new ColumnItem(25, -1));
columnSeries1.Items.Add(new ColumnItem(137, -1));
columnSeries1.Items.Add(new ColumnItem(18, -1));
columnSeries1.Items.Add(new ColumnItem(40, -1));
Model.Series.Add(columnSeries1);
var columnSeries2 = new ColumnSeries();
columnSeries2.StrokeThickness = 1;
columnSeries2.Title = "Series 2";
columnSeries2.Items.Add(new ColumnItem(12, -1));
columnSeries2.Items.Add(new ColumnItem(14, -1));
columnSeries2.Items.Add(new ColumnItem(120, -1));
columnSeries2.Items.Add(new ColumnItem(26, -1));
Model.Series.Add(columnSeries2);
DataContext = this;
}
}
I don't know anything about this OxyPlat, but I do know that most charts are often rendered using hardware APIs. Hardware acceleration is usually error-prone when working outside the expected environment (i.e. a client showing a visible Desktop window).
On application initialization, try disabling hardware acceleration:
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
Another possible tweak is to call DoEvents() before you render your bitmap. Possibly with priority set to SystemIdle. This will make sure your DataContext has been successfully bound.
public static void DoEvents(
DispatcherPriority priority = DispatcherPriority.Background)
{
Dispatcher.CurrentDispatcher.Invoke(new Action(delegate { }), priority);
}

Image control and Image resizing when Stretch is set to Uniform

I have this peculiar problem. I am having a user control . I am making an app for Windows 8.1 where I would choose an image from my Picture gallery. The image would open in my app with Stretch is Uniform and Horizontal And vertical alignment to center.
My user control will appear where I tap on the image. Now the problem is , when the image Stretch was none , I was able to magnify the correct region (around my click) , but now when I make it Stretch to Uniform and Set the horizontal and vertical Alignment to Center , I am getting other pixel information in my user control.
I want to know how to fix it.Any how , the images can be of 2*Full HD also or they can be HD or even less.
Secondly , I want to know the boundaries of the image . With boundaries I want to say that , my user control shouldnt go above the boundaries of the image .
How to implement that. If my code is needed , I would paste it , If required.
Have this video for reference . This is what I have to develop ! I have the user control ready and I am getting exact pixels for Stretch=NONE , and no Horizontal And Vertical Alignment set.
This is my code for my app
I believe the issue is with how you use the control, rather than the image. If you avoid doing the bitmap cropping and replacing, it would speed up dramatically and likely work for all stretch types.
I've modified the source to show this - removing the Cropping completely. If you need cropping for other reasons, you should consider using the unsafe keyword (and property setting to allow) in order to dramatically speed up its use.
Also, to avoid the lagging/jumping upward, I added IsHitTestVisible="False" so that your delta wouldn't be interrupted by hovering over your image.
I see you have the 45-degree code already - since it wasn't in your source, I only added an example of 90 degree rotation when you get to the sides - so you can see how to set a RenderTransformOrigin point.
MainPage.xaml:
<Page x:Name="page1"
x:Class="controlMagnifier.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:controlMagnifier"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="ParentGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" PointerReleased="ParentGrid_OnPointerReleased" >
<Canvas x:Name="InkPresenter" Height="auto" Width="auto">
<Image Stretch="Uniform" x:Name="image2" >
<Image.Source >
<BitmapImage UriSource="/Assets/wallpaper.jpg" />
</Image.Source>
</Image>
</Canvas>
<local:MagnifierUsercontrol x:Name="MagnifyTip" Visibility="Collapsed" ManipulationMode="All"
IsHitTestVisible="False" Height="227" Width="171"
VerticalContentAlignment="Bottom" HorizontalContentAlignment="Center">
</local:MagnifierUsercontrol>
</Grid>
</Page>
MainPage.xaml.cs:
using System;
using Windows.Foundation;
using Windows.Storage;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
namespace controlMagnifier
{
public sealed partial class MainPage : Page
{
public const int XAxis = 200;
public const int YAxis = 435;
private readonly RotateTransform myRotateTransform = new RotateTransform {CenterX = 0.5, CenterY = 1};
private readonly ScaleTransform myScaleTransform = new ScaleTransform {ScaleX = 1, ScaleY = 1};
private readonly TransformGroup myTransformGroup = new TransformGroup();
private readonly TranslateTransform myTranslateTransform = new TranslateTransform();
public WriteableBitmap CurrentBitmapObj, CurrentCroppedImage = null;
public Point currentContactPt, GridPoint;
public Thickness margin;
public PointerPoint pt;
public double xValue, yValue;
public MainPage()
{
InitializeComponent();
ParentGrid.Holding += Grid_Holding;
image2.PointerMoved += InkCanvas_PointerMoved;
image2.PointerReleased += ParentGrid_OnPointerReleased;
margin = MagnifyTip.Margin;
image2.CacheMode = new BitmapCache();
myTransformGroup.Children.Add(myScaleTransform);
myTransformGroup.Children.Add(myRotateTransform);
myTransformGroup.Children.Add(myTranslateTransform);
MagnifyTip.RenderTransformOrigin = new Point(0.5, 1);
MagnifyTip.RenderTransform = myTransformGroup;
}
private void Grid_Holding(object sender, HoldingRoutedEventArgs e)
{
try
{
GridPoint = e.GetPosition(image2);
myTranslateTransform.X = xValue - XAxis;
myTranslateTransform.Y = yValue - YAxis;
MagnifyTip.RenderTransform = myTransformGroup;
MagnifyTip.Visibility = Visibility.Visible;
}
catch (Exception)
{
throw;
}
}
private void InkCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
try
{
pt = e.GetCurrentPoint(image2);
currentContactPt = pt.Position;
xValue = currentContactPt.X;
yValue = currentContactPt.Y;
if (xValue > 300)
{
myRotateTransform.Angle = -90;
}
else if (xValue < 100)
{
myRotateTransform.Angle = 90;
}
else
{
myRotateTransform.Angle = 0;
}
MagnifyTip.RenderTransform = myRotateTransform;
myTranslateTransform.X = xValue - XAxis;
myTranslateTransform.Y = yValue - YAxis;
MagnifyTip.RenderTransform = myTransformGroup;
}
catch (Exception)
{
throw;
}
finally
{
e.Handled = true;
}
}
private async void StoreCrrentImage()
{
try
{
var storageFile =
await
StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/wallpaper.jpg",
UriKind.RelativeOrAbsolute));
using (
var fileStream =
await storageFile.OpenAsync(FileAccessMode.Read))
{
var bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
var writeableBitmap =
new WriteableBitmap(bitmapImage.PixelWidth, bitmapImage.PixelHeight);
fileStream.Seek(0);
await writeableBitmap.SetSourceAsync(fileStream);
CurrentBitmapObj = writeableBitmap;
writeableBitmap.Invalidate();
}
}
catch (Exception)
{
// Graphics g=new Graphics();
throw;
}
finally
{
}
}
private void ParentGrid_OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
MagnifyTip.Visibility = Visibility.Collapsed;
}
}
}
MagnifierUsercontrol.xaml:
<UserControl
x:Class="controlMagnifier.MagnifierUsercontrol"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:controlMagnifier"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Height="227" Width="171">
<Canvas x:Name="controlCanvas" x:FieldModifier="public" Height="Auto" Width="Auto" >
<Grid Height="227" Width="171" HorizontalAlignment="Center" Canvas.Left="0" Canvas.Top="0">
<Border x:FieldModifier="public" x:Name="imgBorder" Width="150" CornerRadius="50,50,50,50" Margin="13,25,13,97">
<Border.Background>
<ImageBrush x:FieldModifier="public" x:Name="image1" />
</Border.Background>
</Border>
<TextBlock x:Name="txtreading" Height="30" Width="80" Margin="0,-145,0,0" FontWeight="Bold" Foreground="Red" FontSize="20" Text="ABC" TextAlignment="Center" />
<!--<Image Height="120" Width="150" Margin="0,-50,0,0" Source="Assets/SmallLogo.scale-100.png" ></Image>-->
<Path x:Name="MagnifyTip" Data="M25.533,0C15.457,0,7.262,8.199,7.262,18.271c0,9.461,13.676,19.698,17.63,32.338 c0.085,0.273,0.34,0.459,0.626,0.457c0.287-0.004,0.538-0.192,0.619-0.467c3.836-12.951,17.666-22.856,17.667-32.33 C43.803,8.199,35.607,0,25.533,0z M25.533,32.131c-7.9,0-14.328-6.429-14.328-14.328c0-7.9,6.428-14.328,14.328-14.328 c7.898,0,14.327,6.428,14.327,14.328C39.86,25.702,33.431,32.131,25.533,32.131z" Fill="#FFF4F4F5" Stretch="Fill" Stroke="Black" UseLayoutRounding="False" Height="227" Width="171" />
</Grid>
</Canvas>
</UserControl>
Let me know if this helps or if there is further toward your specific question.

WPF Viewbox and Image size

I want to create the window that would show list of pictures one below the other. I've created control that contains ViewBox and Image in it:
<UserControl x:Class="..."
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Viewbox Name="viewbox">
<Image Height="10" Name="image" Width="10" HorizontalAlignment="Left" VerticalAlignment="Top" />
</Viewbox>
</Grid>
</UserControl>
public BitmapImage Image
{
get { return image.Source as BitmapImage; }
set { changeImage(value); }
}
public SingleIllustrationViewer()
{
InitializeComponent();
}
private void changeImage(BitmapImage img)
{
System.Drawing.Graphics graphics = System.Drawing.Graphics.FromHwnd(IntPtr.Zero);
float dpiX = graphics.DpiX / 96;
this.image.BeginInit();
this.image.Source = img;
this.image.EndInit();
this.image.Width = img.PixelWidth / img.DpiX * dpiX;
}
and I'm placing Images on window like this:
double margin = 0;
for (int i = 0; i < illustrations.Count; i++)
{
String path = illustrations[i].printVersions.Last<String>();
BitmapImage bmp = new BitmapImage(new Uri(path));
Controls.SingleIllustrationViewer iv = new Controls.SingleIllustrationViewer();
iv.VerticalAlignment = System.Windows.VerticalAlignment.Top;
iv.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
iv.Margin = new Thickness(50, margin, 0, 0);
iv.Image = bmp;
grid.Children.Add(iv);
margin += iv.Image.Height + 20;
}
So, for example, I've placed 3 pictures (all 3 of same width) like this, and received such an interesting behavior: first one is good, second smaller, third smaller than a second. Here is the screen shot:
Maybe someone can tell me why is that so, and how can fix this, to see all those picture in the same width?
Thanks!
Regards, Tomas
Root cause:
You did not specify the Height or Width of the UserControl, so when the first SingleIllustrationViewer is added to the Grid, it will be stretched to occupied all available space until it reaches the edge of the Grid. The same happens to the second one, but it is constrained to a smaller region due to the incremented margin.
The size specified as
d:DesignHeight="300" d:DesignWidth="300"
is only used by designer, set the size like
Height="300" Width="300"
And then, put you viewers in a StackPanel instead of a Grid, then you don't have to calculate the Margin of a viewer base on the last viewer's position. StackPanel is a container that stacks its children in one direction, vertically or horizontally.
for (int i = 0; i < illustrations.Count; i++)
{
String path = illustrations[i].printVersions.Last<String>();
BitmapImage bmp = new BitmapImage(new Uri(path));
Controls.SingleIllustrationViewer iv = new Controls.SingleIllustrationViewer();
iv.VerticalAlignment = System.Windows.VerticalAlignment.Top;
iv.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
iv.Margin = new Thickness(50, 0, 0, 20); //50 px to the left, 20 px to the next child
iv.Image = bmp;
stackPanel1.Children.Add(iv);
}

how can i show different backgrounds in multiple buttons in WPF

I need to show multiple buttons, but each one must have a different background than other buttons, I have been working on it, but I only got to display multiple buttons but with the same background.
Here is the XAML:
<Window x:Class="apple.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="370" Width="525">
<Grid>
<Image Source="C:\Users\Public\Pictures\Sample Pictures\Koala.jpg" Stretch="Fill"/>
<DockPanel Name="dock">
<UniformGrid Name="gridx" DockPanel.Dock="Top" Rows="3" Columns="3" Height="334">
</UniformGrid>
</DockPanel>
</Grid>
</Window>
Also, here is the C# code:
namespace apple
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
masterGUI();
}
public void masterGUI()
{
ImageBrush ib = new ImageBrush();
IconImage[] ico = null;
Bitmap[] img = null;
string[] list = null;
string[] link = Directory.GetFiles(#"C:\ProgramData\Microsoft\Windows\Start Menu\Programs", "*.lnk", SearchOption.AllDirectories);
list = new string[link.Length];
ico = new Icon[link.Length];
img = new Bitmap[link.Length];
for (int n = 0; n < link.Length; n++)
{
System.Windows.Controls.Button newBtn = new Button();
list[n] = System.IO.Path.GetFileNameWithoutExtension(link[n]);
FileToImageIconConverter some = new FileToImageIconConverter(link[n]);
ImageSource imgSource = some.Icon;
ib.ImageSource = imgSource;
newBtn.Background = ib;
newBtn.Content = list[n];
gridx.Children.Add(newBtn);
}
}
}
}
Any idea? thank you.
The ImageBrush needs to be created in the for-loop individually for each item. Otherwise you will end up with the same background for every item.
Also you are approaching this the "wrong" way, in WPF you should use data binding and data templating for this sort of thing instead of imperative looping.

Categories

Resources