I have found this question here: How to populate a WPF grid based on a 2-dimensional array and I wanted to use that the marked solution. And it also seems to work quite nice but there is one problem and that problem is that I am using ellipses to display my data. So every item equals one ellipse.
And here is the problem: The ellipses are requesting on Measure only a size of x = 0, y = 0.
So my problem is that there is displayed nothing. So I tried to create a custom Stackpanel:
public class StretchStackPanel : StackPanel
{
protected override Size MeasureOverride(Size constraint)
{
Size result = constraint;
result.Width = result.Width == Double.PositiveInfinity ? Double.MaxValue : result.Width;
result.Height = result.Height == Double.PositiveInfinity ? Double.MaxValue : result.Height;
if (this.Orientation == System.Windows.Controls.Orientation.Horizontal)
result.Height = result.Width / InternalChildren.Count;
return result;
}
protected override Size ArrangeOverride(Size arrangeSize)
{
var size = base.ArrangeOverride(arrangeSize);
double elementLength;
if (Orientation == System.Windows.Controls.Orientation.Horizontal)
elementLength = size.Width / InternalChildren.Count;
else
elementLength = size.Height / InternalChildren.Count;
double current = 0;
foreach (UIElement e in InternalChildren)
{
Rect result;
if (Orientation == System.Windows.Controls.Orientation.Horizontal)
{
result = new Rect(current, 0, elementLength, size.Height);
current += result.Width;
}
else
{
result = new Rect(0, current, size.Width, elementLength);
current += result.Height;
}
e.Arrange(result);
}
return size;
}
}
But there is a very strange behaviour. There are very very smalle margins between the items and the seem to be random. If I resize you can see them moving.
here are two screenshots:
I also tried to use a Uniformgrid with columns only instead of Stackpanel and set an itemstyle with a fixed height using a ViewBox around the Itemscontrol.
Related
I am creating devexpress xtrareport's xrpicturebox as below.
if (dtPath.Rows.Count <= 0) return;
var panelResimler = new XRPanel {Width = 800};
float x = 0;
float y = 0;
for (var i = 0; i < dtPath.Rows.Count; i++)
{
XRPictureBox xrPictureBox1 = new XRPictureBox
{
ImageUrl = dtPath.Rows[i]["DokumanYolu"].ToString(),
Sizing = ImageSizeMode.AutoSize,
Dpi = 100F,
LocationFloat = new DevExpress.Utils.PointFloat(x, y),
Name = "xrPictureBox1",
};
//if (xrPictureBox1.Width > 800)
//{
// xrPictureBox1.Width = 800;
//}
if (xrPictureBox1.Right > 800)
{
xrPictureBox1.Left = 0;
}
else
{
xrPictureBox1.Top = 0;
}
if (xrPictureBox1.Bottom > y) y = xrPictureBox1.Bottom;
x = xrPictureBox1.Right;
panelResimler.Controls.Add(xrPictureBox1);
}
Detail2.Controls.Add(panelResimler);
The problem is, when I use panel as here image part is not getting visible while size doesnt fit to the report. BTW the comment out part does not help here.
Othervise if I wont use panel that time image streching to severap pages.
are there any solution for limiting image width by page width?
This is what I desire
This is without panel
Thans in advance...
ImageSizeMode.AutoSize mode will not set specific size for control - it will be corrected on printing / document generation process. so you should not look at the control size (Right and Bottom properties), you can change the picture size as a page size divided to count of pictures in line (if i correctly understand your scenario) and set the PictureBox Sizing mode to Zoom image or Squeeze (or smth similar).
Is there a way to get an iteratable collection of all the cells in a DataGrid regardless of whether they are selected or not
If you mean DataGridCells you could use Vincent Sibals helper functions to iterate over all rows DataGrid.Items and columns DataGrid.Columns.
public DataGridCell GetCell(int row, int column)
{
DataGridRow rowContainer = GetRow(row);
if (rowContainer != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
// try to get the cell but it may possibly be virtualized
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
if (cell == null)
{
// now try to bring into view and retreive the cell
DataGrid_Standard.ScrollIntoView(rowContainer, DataGrid_Standard.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
}
return cell;
}
return null;
}
public DataGridRow GetRow(int index)
{
DataGridRow row = (DataGridRow)DataGrid_Standard.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
// may be virtualized, bring into view and try again
DataGrid_Standard.ScrollIntoView(DataGrid_Standard.Items[index]);
row = (DataGridRow)DataGrid_Standard.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
Edit
If grid is your DataGrid you get a list of all DataGridCells like this:
List<DataGridCell> allCellList = new List<DataGridCell>();
for (int i = 0; i < grid.Items.Count; i++)
{
for (int j = 0; j < grid.Columns.Count; j++)
{
allCellList.Add(grid.GetCell(i, j));
}
}
For the sake of convenience (not necessarily performance), you can populate your data (including all cells from all column and rows) from your DataGrid to a single DataTable, which provides functions to help manipulate your data such as iteration, filtering, sorting etc.
// Populate a DataGrid to a DataTable
DataTable dt;
DataView dv = (DataView) myDataGrid.DataSource;
dt = dv.Table.DataSet.Tables[0];
You can subsequently convert any of a specific column to a collection or list using generics in as short as one line of code. See how-do-you-convert-a-datatable-into-a-generic-list:
List<DataRow> myList = dt.Rows.Cast<DataRow>().ToList();
It saves you from writing loops.
To fix the error thrown by the line...
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>
(rowContainer);
Add this routine:
private T GetVisualChild<T>(DataGridRow rowContainer)
{
throw new NotImplementedException();
}
Windows 7 (64 bit), .NET 4 (32 bit app)
I have a subclassed System.Windows.Forms.ListView comprising 2 columns displayed
in "Details" view. Only text fields are involved. The list comprises about 100
rows. On initial display all fields are drawn clearly but when scrolling or
"paging" with the scroll bar the text of some fields in the first column becomes
unreadable. It appears to be overwriten with random lines and blotches.
Is there anything that I can do to ensure that the text is clearly drawn in column 0?
The effect is diminished (clarity improved) when using remote desktop across a
LAN.
The effect disappears (all text is drawn clearly) when using remote desktop
across a WAN.
The ListView has always drawn perfectly on Windows XP.
For the purposes of a stripped down test, column header and DrawItem calls are ingored. The problem area is OnDrawSubItem which comprises the code
protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
{
using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap))
{
Rectangle rect = new Rectangle(e.Bounds.Left
,e.Bounds.Top, e.Bounds.Width, e.Bounds.Height);
e.Graphics.DrawString(e.SubItem.Text, this.Font, Brushes.Black
,rect, sf);
}
base.OnDrawSubItem(e);
}
The following is the complete code that reproduces the problem:
using System;
using System.Windows.Forms;
using System.Drawing;
///
/// Build by saving to a file called LVTrial.cs and then executing "csc LVTrial.cs"
/// Scroll list up and down on a windows 7 box and the first column of text is corrupted.
///
class MyListView : ListView
{
Random randomiser = new Random();
private const int NUM_ROWS = 100;
private const int NUM_COLS = 2;
public MyListView()
{
this.Location = new System.Drawing.Point(23, 25);
this.OwnerDraw = true;
this.Size = new System.Drawing.Size(625, 387);
this.TabIndex = 0;
this.UseCompatibleStateImageBehavior = false;
this.View = System.Windows.Forms.View.Details;
for (int ii = 0; ii < NUM_COLS; ii++)
{
this.Columns.Add((
(System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())));
}
for (int ii = 0; ii < NUM_ROWS; ii++)
{
this.Items.Add( new ListViewItem(
new string[NUM_COLS] { CreateRandomString(1, 6), CreateRandomString(1, 6) } ) );
}
}
protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
{
using (StringFormat sf = new StringFormat(StringFormatFlags.NoWrap))
{
Rectangle rect = new Rectangle(e.Bounds.Left
,e.Bounds.Top, e.Bounds.Width, e.Bounds.Height);
e.Graphics.DrawString(e.SubItem.Text, this.Font, Brushes.Black
,rect, sf);
}
base.OnDrawSubItem(e);
}
private string CreateRandomString(int minLength, int maxLength)
{
string str = string.Empty;
int length = randomiser.Next(minLength, maxLength + 1);
for (int ii = 0; ii < length; ii++)
{
int asciiChar = randomiser.Next(32, 126); // ascii range
str += Convert.ToChar(asciiChar);
}
return str;
}
}
class LVTrial : Form
{
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new LVTrial());
}
private LVTrial()
{
MyListView myListView = new MyListView();
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(674, 440);
this.Controls.Add(myListView);
this.Text = "LVTrial";
}
}
I have recorded this as a Windows 7 bug at https://connect.microsoft.com/VisualStudio/feedback/details/657909/subclassed-listview-column-0-displays-corrupted-text-on-windows-7
My own workaround for the problem was to insert an additional column at position 0. I now draw a rectangle with a transparent brush in column 0 for each item. All of which stops the text in the column to the right being drawn corrupt. I imagine drawing an image would achieve the same thing but I have not tried it. You can't hide this dummy column as the problem simply transfers to the second column (i.e. the first visible coolumn).
Another tip is that it seems to be performance related. The bug was more likely to occur with 100 items in the list view than 10,000.
i have a small demo app with a grid. this grid contains a image. i use the following code to scale and translate the image with touch.
private void manipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
Matrix matrix = imagematrix.Matrix;
matrix.Translate(e.DeltaManipulation.Translation.X, e.DeltaManipulation.Translation.Y);
matrix.ScaleAt(e.DeltaManipulation.Scale.X, e.DeltaManipulation.Scale.Y,
e.ManipulationOrigin.X, e.ManipulationOrigin.Y);
imagematrix.Matrix = matrix;
e.Handled = true;
}
The matrix is placed at rendertransformation property on the image.
I would like to have the same functionality in a other demo app without touch but with mouse event handlers.
I tried something like this for the translation on mouse move but its not the same :(
protected override void OnMouseMove(MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Vector delta = lastPoint - e.GetPosition(canvascontrol);
Matrix matrix = PART_MATRIX.Matrix;
if(delta.X > 0)
matrix.OffsetX += 1;
else
matrix.OffsetX -= 1;
if (delta.Y > 0)
matrix.OffsetY += 1;
else
matrix.OffsetY -= 1;
imagematrix.Matrix = matrix;
}
base.OnMouseMove(e);
}
lastPoint is the first point onmouseleftbuttondown.
Thanks.
I am not sure, if this is the answer you are looking for but, the Thumb control gives you a DragDelta, if you wrap a Thumb into a template and then assign the template to the image object, or assign the image as a template to the Thumb.
my code below is supposed to display N lines per inch. instead i get a little more than N lines per inch. the distance between lines is somewhat smaller. in addition, changing the screen resolution makes the distance between lines change too. does anyone know how to handle that?
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace MyApp
{
class MyControl : Control
{
private readonly ContainerVisual container = new ContainerVisual();
private readonly DrawingVisual drawing = new DrawingVisual();
private void RenderDrawing()
{
var s = PresentationSource.FromVisual(this);
var dpiX = 96 * s.CompositionTarget.TransformToDevice.M11;
var dpiY = 96 * s.CompositionTarget.TransformToDevice.M22;
double N = 1;
using (var c = drawing.RenderOpen())
{
var p = new Pen(new SolidColorBrush(Colors.Black), 1);
for (int i = 0; i < 10; i++)
{
var x = i * dpiX / N;
c.DrawLine(p, new Point(x, 0), new Point(x, 100));
}
}
}
protected override Size ArrangeOverride(Size s)
{
RenderDrawing();
return s;
}
protected override Visual GetVisualChild(int index)
{
return container;
}
protected override Size MeasureOverride(Size s)
{
return new Size();
}
protected override int VisualChildrenCount
{
get { return 1; }
}
public MyControl()
{
container.Children.Add(drawing);
AddVisualChild(container);
}
}
}
this article seems to discuss the same problem: WPF DPI issues
there is no solution to this problem other than asking the user to set the correct DPI settings that correspond to the physical DPI of the screen. a workaround that i found that makes life a little easier is to use WPF application level scaling as described here: http://www.odewit.net/ArticleContent.aspx?id=WpfDpiScaling&lang=en&format=html
Not sure if this would accomplish what you are looking for, but it should help if the issue has to do with rounding. As I said in comments, your code looks mostly correct, I think it is a rounding issue with the dpi computation. Since you are desiring to render based on 96 dpi, compute the coordinates based on 96dpi and then convert the points to your device. I wrote this more for clarity, you could use a single array of points and just remember that i is the start point and i+1 is the end point and then you would only have to make a single call to transform the points.
private void RenderDrawing()
{
var s = PresentationSource.FromVisual(this);
var dpiX = 96;
int numberOfLines = 10;
double N = 1;
double spacing = dpiX / N;
var startPoints = new Point[numberOfLines]();
var endPoints = new Point[numberOfLines]();
for (int i = 0; i < numberOfLines; i++)
{
var x = i * spacing;
startPoints[i] = new Point(x, 0);
endPoints[i] = new Point(x, 100);
}
s.CompositionTarget.TransformToDevice.Transform(startPoints);
s.CompositionTarget.TransformToDevice.Transform(endPoints);
using (var c = drawing.RenderOpen())
{
using (var p = new Pen(new SolidColorBrush(Colors.Black), 1))
{
for(int i=0; i < numberOfLines; i++)
{
c.DrawLine(p, startPoints[i], endPoints[i]);
}
}
}
}