I have a code snippet which is currently returned as Grid.
private Grid GetImage(PlacemarkList locationDetail)
{
Grid gridPushPin = new Grid();
ImageBrush img = new ImageBrush();
img.ImageSource = locationDetail.preferredCashback.Equals("1") ? new BitmapImage {
UriSource = Constants.CashbackIconUri,
DecodePixelWidth = 36,
DecodePixelHeight = 59
} : new BitmapImage {
UriSource = Constants.ATMIconUri,
DecodePixelWidth = 36, DecodePixelHeight = 59
};
TextBlock IndexText = new TextBlock();
IndexText.TextAlignment = TextAlignment.Center;
IndexText.Text = locationDetail.IndexNum.ToString();
gridPushPin.Background = img;
gridPushPin.Tag = locationDetail.bankAddress;
gridPushPin.Tap += grid_Tap;
return gridPushPin;
}
But I want to return the Grid as a Image(Convert the Grid I am generating to Image). Can anybody please help how to accomplish that.
You can use a VisualBrush to paint a copy of any UIElement onto any other. How about something like this:
<Rectangle Width="150" Height="150">
<Rectangle.Fill>
<VisualBrush Visual="{Binding ElementName=NameOfYourGrid}" />
</Rectangle.Fill>
</Rectangle>
Hey did you check this subject. I think what you need is here.
How do I save all content of a WPF ScrollViewer as an image
public class MyWrapperClass
{
private DataGrid dataGrid;
public MyWrapperClass(DataGrid grid)
{
this.dataGrid = grid;
}
public DataGrid MyGrid
{
get
{
return this.grid;
}
set
{
this.grid = value;
}
}
public ImageBrush MyImageBrush
{
get
{
this.grid.Background as ImageBrush;
}
set
{
this.grid.Background = value;
}
}
}
You are creating a Grid, so you will return a Grid.
Create an image instead. Something like:
Image image = new Image();
image.Source = "myImageURL";
This is from memory so actual code may vary depending on what you need to do exactly.
Basically the Source of the image needs to be set similarly to how you're setting ImageSource in your current code, but you may opt to use pack URLs to use an image stored as a resource instead.
Edit after clarifications in comments: So you want to get the grid control as an image. This answer should help.
Related
I have large treeview full of textboxes, each with tooltip containing a unique image. The image is stored in a property as a bytearray and I bind to it. Every time a new tooltip is displayed more memory is used.
I will be scaling the image, but that doesn't address the root of the problem. If there a way to free the memory used after the tooltip is no longer displayed?
<TextBlock.ToolTip>
<StackPanel>
<Image MaxWidth="650"
MaxHeight="400"
Source="{Binding ImageAsByteArray}"/>
<TextBlock Text="{Binding FilePath, StringFormat='Full Path: {0}'}" />
</StackPanel>
</TextBlock.ToolTip>
The tooltip can be set to any framework element, so could dynamically create this as an object behind the scenes:
<TextBlock ToolTip={Binding ToolTip} />
Then your view model or code behind could dynamically create this object and handle the loaded/unloaded event to capture when the tooltip displays.
I've done it below with a canvas is case you want to add other children besides the image:
var tooltipCanvas = new Canvas();
var img = new Image();
tooltipCanvas.Children.Add(img);
tooltipCanvas.Width = 500;
tooltipCanvas.Height = 500;
tooltipCanvas.Loaded += Tooltip_Loaded;
tooltipCanvas.Unloaded += Tooltip_Unloaded;
Then you could populate the image source just for the time the image is shown using the loaded and unloaded event handlers:
private void Tooltip_Loaded(object sender, RoutedEventArgs e)
{
var canvas = sender as Canvas;
var img = canvas.Children[0] as Image;
img.Source = /* get your image bytes */;
}
private void Tooltip_Unloaded(object sender, RoutedEventArgs e)
{
var canvas = sender as Canvas;
var img = canvas.Children[0] as Image;
img.Source = null;
}
I have been tasked with taking an existing list of transparent .png images (currently housed within an ImageList) and displaying them in a WPF DataGrid based on the ImageID column.
I have set up the DataGridColumn as follows:
_dataTemplateColumn = new DataGridTemplateColumn();
_dataTemplateColumn.Header = "";
FrameworkElementFactory _factory = new FrameworkElementFactory(typeof(Image));
Binding _binding = new Binding("Image");
_binding.Mode = BindingMode.TwoWay;
_factory.SetValue(Image.SourceProperty, _binding);
DataTemplate _cellTemplate = new DataTemplate();
_cellTemplate.VisualTree = _factory;
_dataTemplateColumn.CellTemplate = _cellTemplate;
Style _style = new Style();
_style.Setters.Add(new Setter(BackgroundProperty, Brushes.Transparent));
_dataTemplateColumn.CellStyle = _style;
I then create a Custom Object at runtime which includes the image for me and run the following 2 methods on the Image, the first to resize it and the second to convert it into a Bitmap rather than a BitmapImage (which is the only format I have managed to get it working in WPF with so far):
public static Bitmap ResizeImage(this Bitmap Bitmap, Size size)
{
try
{
Bitmap _bitmap = new Bitmap(size.Width, size.Height);
using (Graphics _graphic = Graphics.FromImage((Image)_bitmap))
{
_graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
_graphic.DrawImage(Bitmap, 0, 0, size.Width, size.Height);
}
_bitmap.MakeTransparent(Color.Magenta);
return _bitmap;
}
catch (Exception ex)
{
throw ex;
}
}
public static Bitmap ToBitmap(this BitmapImage BitmapImage)
{
using (MemoryStream _stream = new MemoryStream())
{
BitmapEncoder _encoder = new BmpBitmapEncoder();
_encoder.Frames.Add(BitmapFrame.Create(BitmapImage));
_encoder.Save(_stream);
System.Drawing.Bitmap _bitmap = new System.Drawing.Bitmap(_stream);
_bitmap.MakeTransparent(Color.Magenta);
return new Bitmap(_bitmap);
}
}
The Image is being displayed in the correct size and position in the DataGrid but the transparency is not preserved from the .png format. If anyone knows a better method for me (perhaps it is more correct to take the Image into a resource file first for example?) or a way to get the transparency working within my current code it would be most appreciated!
The following example gives you an idea of how it may look like:
XAML:
<Window ...>
<Window.Resources>
<DataTemplate x:Key="ImageCellTemplate">
<Image Source="{Binding Image}" Width="100"/>
</DataTemplate>
</Window.Resources>
<Grid>
<DataGrid x:Name="dataGrid" AutoGenerateColumns="False"/>
</Grid>
</Window>
Code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var col = new DataGridTemplateColumn();
col.CellTemplate = (DataTemplate)Resources["ImageCellTemplate"];
dataGrid.Columns.Add(col);
foreach (var file in Directory.EnumerateFiles(#"C:\Users\Public\Pictures\Sample Pictures", "*.jpg"))
{
dataGrid.Items.Add(new DataItem { Image = file });
}
}
}
public class DataItem
{
public string Image { get; set; }
}
I am trying to display an icon using an image source(.jpg). I create a Icon property in view model and try to assign it the path of the image but I do not see any image in the view. I tried converting the path to Bitmap image but doesn't work. Is there anything I am missing here?
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}"/>
<Image Source="{Binding Path=Icon}"></Image>
</StackPanel>
BitmapImage img = new BitmapImage();
img.BeginInit();
img.CacheOption = BitmapCacheOption.OnLoad;
img.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
img.UriSource = new Uri("C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg", UriKind.Absolute);
img.EndInit();
Icon = img;
I ran into this myself once and, though maybe not the best solution, the following worked for me.
1. Add the images to your project, for example:
Create a folder images/icons to your project and add the images there.
Set build action of images to Content (copy if newer)
2. Create an ImageSource property:
public ImageSource YourImage
{
get { return _yourImage; }
set
{
_yourImage = value;
NotifyOfPropertyChange(() => YourImage);
}
}
(Note: I use caliburn micro to assist in binding)
3. Update the the ImageSource like this:
if(!string.IsNullOrEmpty("TheImageYouWantToShow"))
{
var yourImage = new BitmapImage(new Uri(String.Format("Images/Icons/{0}.jpg", TheImageYouWantToShow), UriKind.Relative));
yourImage.Freeze(); // -> to prevent error: "Must create DependencySource on same Thread as the DependencyObject"
YourImage = yourImage;
}
else
{
YourImage = null;
}
4. Bind source attribute to YourImage property:
(you already did this)
When I have the following setup, the last column having a width of * causes the datagrid to create huge horizontal scrollbars (extends grid to several widths of the screen). I'm not really sure why this is, but I really need a way to avoid that. I don't want to have to "simulate" column's with * lengths.
edit: Apparently I'm not the only one who noticed this.
http://connect.microsoft.com/VisualStudio/feedback/details/559644/silverlight-4-datagrid-star-column-width
Xaml:
<ScrollViewer Padding="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" >
<sdk:DataGrid AutoGenerateColumns="False" x:Name="dg"/>
</ScrollViewer>
Code:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
dg.Columns.Add(new DataGridTextColumn { Binding = new Binding("A"), Header = "A" });
dg.Columns.Add(new DataGridTextColumn { Binding = new Binding("B"), Header = "B" });
dg.Columns.Add(new DataGridTextColumn { Binding = new Binding("C"), Header = "C" });
dg.Columns[2].Width = new DataGridLength(1, DataGridLengthUnitType.Star);
dg.ItemsSource = new[]
{
new I { A = "SAF", B = "SAF", C = "SAF" },
new I { A = "SAF", B = "SAF", C = "SAF" },
new I { A = "SAF", B = "SAF", C = "SAF" }
};
}
public class I
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
you need to put a maxwidth on the scrollviewer? otherwise width is defaulted to auto and maxwidth is infinity
If you remove
dg.Columns[2].Width = new DataGridLength(1, DataGridLengthUnitType.Star);
the problem should go away. Can I ask why you want the last column to take the rest of the space? The column actually knows to resize itself properly to fit its cell size and column header size.
Also, if you don't specify the column's width, then you don't really need a scrollviewer to scroll and see all the columns. The datagrid has a scrollviewer built in and when there are columns out of the screen the horizontal scrollbar will apear.
I hope this helps. :)
I have a DataTable containing an arbitrary number of columns and rows which I am trying to print out. The best luck I've had so far is by putting the data into a Table and then adding the table to a FlowDocument.
So far so good. The problem I have right now is that the Table only "wants" to take up about half of the document's width. I've already set the appropriate values for the FlowDocument's PageWidth and ColumnWidth properties, but the Table doesn't seem to want to stretch to fill up the allotted space?
In order to set your FlowDocument contents to the full available widh you must first know the width of the page. The property you need to set that takes care of the content length is the ColumnWidth prop on the FlowDocument.
I usualy create a "PrintLayout" helper class to keep known presets for the Page width/hight and Padding. Wou can snif presets from Ms Word and fill more.
The class for PrintLayout
public class PrintLayout
{
public static readonly PrintLayout A4 = new PrintLayout("29.7cm", "42cm", "3.18cm", "2.54cm");
public static readonly PrintLayout A4Narrow = new PrintLayout("29.7cm", "42cm", "1.27cm", "1.27cm");
public static readonly PrintLayout A4Moderate = new PrintLayout("29.7cm", "42cm", "1.91cm", "2.54cm");
private Size _Size;
private Thickness _Margin;
public PrintLayout(string w, string h, string leftright, string topbottom)
: this(w,h,leftright, topbottom, leftright, topbottom) {
}
public PrintLayout(string w, string h, string left, string top, string right, string bottom) {
var converter = new LengthConverter();
var width = (double)converter.ConvertFromInvariantString(w);
var height = (double)converter.ConvertFromInvariantString(h);
var marginLeft = (double)converter.ConvertFromInvariantString(left);
var marginTop = (double)converter.ConvertFromInvariantString(top);
var marginRight = (double)converter.ConvertFromInvariantString(right);
var marginBottom = (double)converter.ConvertFromInvariantString(bottom);
this._Size = new Size(width, height);
this._Margin = new Thickness(marginLeft, marginTop, marginRight, marginBottom);
}
public Thickness Margin {
get { return _Margin; }
set { _Margin = value; }
}
public Size Size {
get { return _Size; }
}
public double ColumnWidth {
get {
var column = 0.0;
column = this.Size.Width - Margin.Left - Margin.Right;
return column;
}
}
}
next on your FlowDocument you can set the presets
On Xaml
<FlowDocument x:Class="WpfApp.MyPrintoutView"
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:local="clr-namespace:WpfApp"
mc:Ignorable="d"
PageHeight="{Binding Height, Source={x:Static local:PrintLayout.A4}}"
PageWidth="{Binding Width, Source={x:Static local:PrintLayout.A4}}"
PagePadding="{Binding Margin, Source={x:Static local:PrintLayout.A4}}"
ColumnWidth="{Binding ColumnWidth, Source={x:Static local:PrintLayout.A4}}"
FontFamily="Segoe WP"
FontSize="16" ColumnGap="4">
<!-- flow elements -->
</FlowDocument>
By code
FlowDocument result = new WpfApp.MyPrintoutView();
result.PageWidth = PrintLayout.A4.Size.Width;
result.PageHeight = PrintLayout.A4.Size.Height;
result.PagePadding = PrintLayout.A4.Margin;
result.ColumnWidth = PrintLayout.A4.ColumnWidth;
I had some luck with this: How to set the original width of a WPF FlowDocument, although it only took up about 90% of the space.