Xamarin forms Grid within a scrollView - Performance issue - c#

I have an page that got a scrollview, with inside a Grid.
Each cell of grid got an image.
I load images with ffimageloader.
Images are from DCIM/Images library
Works good, but when I got many images on the Grid, I have memories issues.
I can't figure how to draw only cells that are currently visible on the scrollview. I see something like that on ffimageloader wiki, but how to adapt the
_myListView.ForcePdfThumbnalisRedraw();
to Grid cells actually visible on screen?
myScrollView.ScrollStateChanged += (object sender, ScrollStateChangedEventArgs scrollArgs) => {
switch (scrollArgs.ScrollState)
{
case ScrollState.Fling:
ImageService.Instance.SetPauseWork(true); // all image loading requests will be silently canceled
break;
case ScrollState.Idle:
ImageService.Instance.SetPauseWork(false); // loading requests are allowed again
// Here you should have your custom method that forces redrawing visible list items
_myListView.ForcePdfThumbnailsRedraw();
break;
}
};
Here is the page ( Slightly lighter because too much nonsense code for the problem )
int GridCellWidth, GridCellHeight;
Grid headerGrid, contentGrid, footerGrid, pageGrid;
ScrollView galerieScrollView;
StackLayout headerLayout, footerLayout;
public Galer()
{
contentGrid = new Grid();
contentGrid.VerticalOptions = LayoutOptions.Center;
contentGrid.BackgroundColor = Color.Transparent;
GridCellWidth = App.ScreenWidthD / 4;
GridCellHeight = App.ScreenHeightD / 4;
contentGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(GridCellWidth) });
contentGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(GridCellWidth) });
contentGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(GridCellWidth) });
contentGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(GridCellWidth) });
bool bigOne = false;
int index;
int row = 0;
for (index = 0; index < imagesUrls.Count; index++)
{
if (index + 5 <= imagesUrls.Count)
{
if (!bigOne)
{
contentGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(GridCellWidth) });
contentGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(GridCellWidth) });
List<string> imagesToDraw = imagesUrls.GetRange(index, 5);
AddToRowWithLeftBigImage(imagesToDraw, row, contentGrid);
bigOne = true;
index = index + 5;
}
else
{
contentGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(GridCellWidth) });
contentGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(GridCellWidth) });
List<string> imagesToDraw = imagesUrls.GetRange(index, 5);
AddToRowWithRightBigImage(imagesToDraw, row, contentGrid);
index = index + 5;
bigOne = false;
}
row = row + 2;
}
}
if (imagesUrls.Count() - index > 0)
{
contentGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(GridCellWidth) });
int lastPosition = index - imagesUrls.Count();
int steelAvialable = Math.Abs(imagesUrls.Count() - index);
List<string> imagesToDraw = imagesUrls.GetRange(lastPosition, steelAvialable);
for (var i = 0; i < imagesToDraw.Count(); i++)
{
contentGrid.Children.Add(GetCachedImageFromStringUrl(imagesToDraw[i]), row, 0);
}
}
galerieScrollView = new ScrollView
{
Content = contentGrid
};
galerieScrollView.BackgroundColor = Color.Transparent;
pageGrid = new Grid();
pageGrid.Padding = new Thickness(0, 0, 0, 0);
//pageGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(2, GridUnitType.Star) });
pageGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(9, GridUnitType.Star) });
pageGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
pageGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
//pageGrid.Children.Add(headerLayout, 0, 0);
//pageGrid.Children.Add(contentGrid, 0, 0);
pageGrid.Children.Add(galerieScrollView, 0, 0);
//pageGrid.Children.Add(footerLayout, 0, 1);
Content = pageGrid;
}
private void AddToRowWithRightBigImage(List<string> imageToDraw, int currentRow, Grid intoThatGrid)
{
var image = GetCachedImageFromStringUrl(imageToDraw[0], GridCellWidth * 2, GridCellWidth * 2, GridCellWidth);
intoThatGrid.Children.Add(image, 0, currentRow);
Grid.SetColumnSpan(image, 2);
Grid.SetRowSpan(image, 2);
intoThatGrid.Children.Add(GetCachedImageFromStringUrl(imageToDraw[1], GridCellWidth, GridCellWidth), 2, currentRow);
intoThatGrid.Children.Add(GetCachedImageFromStringUrl(imageToDraw[2], GridCellWidth, GridCellWidth), 3, currentRow);
intoThatGrid.Children.Add(GetCachedImageFromStringUrl(imageToDraw[3], GridCellWidth, GridCellWidth), 2, currentRow + 1);
intoThatGrid.Children.Add(GetCachedImageFromStringUrl(imageToDraw[4], GridCellWidth, GridCellWidth), 3, currentRow + 1);
}
private void AddToRowWithLeftBigImage(List<string> imageToDraw, int currentRow, Grid intoThatGrid)
{
intoThatGrid.Children.Add(GetCachedImageFromStringUrl(imageToDraw[1], GridCellWidth, GridCellWidth), 0, currentRow);
intoThatGrid.Children.Add(GetCachedImageFromStringUrl(imageToDraw[2], GridCellWidth, GridCellWidth), 1, currentRow);
intoThatGrid.Children.Add(GetCachedImageFromStringUrl(imageToDraw[3], GridCellWidth, GridCellWidth), 0, currentRow + 1);
intoThatGrid.Children.Add(GetCachedImageFromStringUrl(imageToDraw[4], GridCellWidth, GridCellWidth), 1, currentRow + 1);
var image = GetCachedImageFromStringUrl(imageToDraw[4], GridCellWidth * 2, GridCellWidth * 2, GridCellWidth);
intoThatGrid.Children.Add(image, 2, currentRow);
Grid.SetColumnSpan(image, 2);
Grid.SetRowSpan(image, 2);
}
private CachedImage GetCachedImageFromStringUrl(string url, int heightRequest = 200, int widthRequest = 200, int downSample = 50)
{
CachedImage image = new CachedImage();
image.Source = url;
image.HeightRequest = heightRequest;
image.WidthRequest = widthRequest;
image.DownsampleWidth = downSample;
image.LoadingPlaceholder = "loading.png";
image.Transformations = new System.Collections.Generic.List<ITransformation>() {
new CropTransformation(1, image.Width / 2 - heightRequest, image.Height / 2 - widthRequest)
};
/*image.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() => {
Navigation.PushModalAsync(new ViewImagePage(image));
}),
NumberOfTapsRequired = 1
});*/
return image;
}
I got this as result

Related

Grid does not fill the whole window, why?

I have written a UI for an Game of Life (Automation Theory) and the algorithm works just fine. I have also created a pop-up which will start first and where you can set the amount of rows and columns the game should have. This works also fine. Somehow my Grid only fills a small amount of the space in the window (Like it would only be in the left top cell of another Grid). I cannot work out why this is happening. Help would be much appreciated. I am aware that the code is quit complex and messy at this point. The GameCreation() Method is calling the popup window first. After that I declare some variables and my grid. Then I create rows and columns and button which I store in the grid as well. There are no errors or exceptions.
This is how the window looks like:
private void GameCreation()
{
//Pop-up Fenster aufrufen und eingaben in rowCount und colCount speichern
List<int> list = new List<int>();
list = OptionsWindow();
//Variablen deklarieren
int nameNum = 1;
int rowCount = list[0];
int colCount = list[1];
Button[,] buttons = new Button[rowCount, colCount];
Grid MainGrid = new Grid();
Window1.Content = MainGrid;
for (int i = 0; i < rowCount; i++)
{
for (int j = 0; j < colCount; j++)
{
// create Grid.RowDefinition and Grid.ColumnDefinition based on rowCount and colCount
RowDefinition row = new RowDefinition();
GridLengthConverter gridLengthConverter = new GridLengthConverter();
row.Height = (GridLength)gridLengthConverter.ConvertFrom("*");
MainGrid.RowDefinitions.Add(row);
ColumnDefinition column = new ColumnDefinition();
column.Width = (GridLength)gridLengthConverter.ConvertFrom("*");
MainGrid.ColumnDefinitions.Add(column);
// Button erstellen
Button button = new Button
{
Name = "B" + nameNum,
Background = Brushes.Gray,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
Padding = new Thickness(1, 1, 1, 1)
};
button.Click += ChangeColor;
//den Button zum Grid hinzufügen an der richtigen Stelle
Grid.SetRow(button, i);
Grid.SetColumn(button, j);
MainGrid.Children.Add(button);
//Button buttons[,] hinzufügen
buttons[i, j] = button;
nameNum++;
}
}
//resetButton deklarieren
Button resetButton = new()
{
Name = "resetButton",
Background = Brushes.DodgerBlue,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
Padding = new Thickness(1, 1, 1, 1),
Content = new Image
{
Source = new BitmapImage(new Uri("C:\\Users\\myname\\source\\repos\\GameOfLife\\GameOfLifeApp\\ResetButton2.png"))
}
};
resetButton.Click += Reset;
Grid.SetRow(resetButton, rowCount);
Grid.SetColumn(resetButton, 0);
Grid.SetColumnSpan(resetButton, 1);
//StartButton deklarieren
RowDefinition row2 = new RowDefinition();
GridLengthConverter gridLengthConverter2 = new GridLengthConverter();
row2.Height = (GridLength)gridLengthConverter2.ConvertFrom("*");
MainGrid.RowDefinitions.Add(row2);
Button startButton = new()
{
Name = "startButton",
Background = Brushes.DodgerBlue,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
Padding = new Thickness(1, 1, 1, 1),
Content = "Start",
HorizontalContentAlignment = HorizontalAlignment.Center,
VerticalContentAlignment = VerticalAlignment.Center,
Foreground = Brushes.White
};
startButton.Click += Start;
Grid.SetRow(startButton, rowCount);
Grid.SetColumn(startButton, 1);
int colSpan = colCount - 2;
Grid.SetColumnSpan(startButton, colSpan);
//clearButton deklarieren
Button clearButton = new()
{
Name = "clearButton",
Background = Brushes.DodgerBlue,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
Padding = new Thickness(1, 1, 1, 1),
Content = new Image
{
Source = new BitmapImage(new Uri("C:\\Users\\myname\\source\\repos\\GameOfLife\\GameOfLifeApp\\ClearButton.png"))
}
};
clearButton.Click += Clear;
Grid.SetRow(clearButton, rowCount);
Grid.SetColumn(clearButton, colCount - 1);
Grid.SetColumnSpan(clearButton, 1);
//Button Array richtig besetzen
int[,] startArray = new int[rowCount, colCount];
int rowLength = startArray.GetLength(0);
int colLength = startArray.GetLength(1);
startArray = Phasen.StartArray(startArray);
buttons = TranslatetoButtonArray(startArray, buttons, rowLength, colLength);
//Funktionsbutton MainGrid hinzufügen
MainGrid.Children.Add(startButton);
MainGrid.Children.Add(clearButton);
MainGrid.Children.Add(resetButton);
}
I have tried setting the heigth and width of the Grid to auto but that doesnt change anything. When i had a fix amount of buttons and declared the Grid aswell as the buttons in the .xaml file there was no such problem.
The reason I think you have this issue is because your code runs after measure and arrange have been done for your window.
I'm not sure why adding the grid doesn't force that again but I have a suggestion could make your problem go away.
Add
Window1.InvalidateVisual();
To the end of your code.
If that still doesn't work then try instead:
Dispatcher.CurrentDispatcher.InvokeAsync(new Action(() =>
{
Window1.InvalidateVisual();
}), DispatcherPriority.ContextIdle);
Still no joy then try not showing whatever this popup is. Maybe you're showing that as modal.
This approach of building everything out in code is inadvisable. Datatemplating is perfectly capable of working fast enough for basic games.

Object not shown on Canvas (WPF Application)

In this Application, i have a car class with a method called Spawn (which should draw the object on a Canvas which i defined in the XAML file). I call the Method in MainWindow, but when I run my program, there is no car being drawn onto the Canvas.
Here is the Spawn method:
public void Spawn(Canvas cvs)
{
cvs = new Canvas();
cvs.Children.Clear();
carBody.Width = 70;
carBody.Height = 120;
carBody.Background = new SolidColorBrush(Color);
Canvas.SetLeft(carBody, SpawnLocation.X);
Canvas.SetTop(carBody, SpawnLocation.Y);
Rectangle[] tires = new Rectangle[4];
Rectangle[] windows = new Rectangle[2];
Label lblBrand = new Label();
RotateTransform rotation = new RotateTransform();
// Reifen
tires[0] = new Rectangle()
{
Fill = Brushes.Black,
Width = 20,
Height = 30
};
Canvas.SetLeft(tires[0], -9);
Canvas.SetTop(tires[0], 18);
tires[1] = new Rectangle()
{
Fill = Brushes.Black,
Width = 20,
Height = 30
};
Canvas.SetLeft(tires[1], 61);
Canvas.SetTop(tires[1], 18);
tires[2] = new Rectangle()
{
Fill = Brushes.Black,
Width = 20,
Height = 30
};
Canvas.SetLeft(tires[2], -9);
Canvas.SetTop(tires[2], 80);
tires[3] = new Rectangle()
{
Fill = Brushes.Black,
Width = 20,
Height = 30
};
Canvas.SetLeft(tires[3], 61);
Canvas.SetTop(tires[3], 80);
// Fenster
windows[0] = new Rectangle() // Front
{
Fill = Brushes.White,
Width = 50,
Height = 40
};
Canvas.SetLeft(windows[0], 0);
Canvas.SetTop(windows[0], 0);
windows[1] = new Rectangle() // rear
{
Fill = Brushes.White,
Width = 50,
Height = 50
};
Canvas.SetLeft(windows[1], 0);
Canvas.SetTop(windows[1], 0);
// Label Automarke
lblBrand.Width = 40;
lblBrand.Height = 23;
lblBrand.Content = Brand;
// Add2Canvas
for (int i = 0; i < tires.Length; i++)
carBody.Children.Add(tires[i]);
for (int i = 0; i < windows.Length; i++)
carBody.Children.Add(windows[i]);
carBody.Children.Add(lblBrand);
if (Direction == "nord")
{
rotation.Angle = 0;
rotation.CenterX = SpawnLocation.X;
rotation.CenterY = SpawnLocation.Y;
carBody.RenderTransform = rotation;
}
else if (Direction == "süd")
{
rotation.Angle = 180;
rotation.CenterX = SpawnLocation.X;
rotation.CenterY = SpawnLocation.Y;
carBody.RenderTransform = rotation;
}
else if (Direction == "west")
{
rotation.Angle = 90;
rotation.CenterX = SpawnLocation.X;
rotation.CenterY = SpawnLocation.Y;
carBody.RenderTransform = rotation;
}
else if (Direction == "ost")
{
rotation.Angle = 270;
rotation.CenterX = SpawnLocation.X;
rotation.CenterY = SpawnLocation.Y;
carBody.RenderTransform = rotation;
}
cvs.Children.Add(carBody);
}
Calling the methodMainWindow:
Car car1;
public MainWindow()
{
InitializeComponent();
car1 = new Car("Audi", Colors.Red);
car1.Direction = "west";
car1.SpawnLocation = new Point(550, 340);
car1.Spawn(gameScreen);
}
Thanks in advance!
Fixed it! I initialized the argmument of my Spawn method, it now works after I deleted it.
My method looked like this first:
public void Spawn(Canvas cvs)
{
cvs = new Canvas();
cvs.Children.Clear();
carBody.Width = 70;
I initialized my the Argument, but since i don't wanna create a new Canvas, i deleted these two first lines of my method.
public void Spawn(Canvas cvs)
{
carBody.Width = 70;
carBody.Height = 120;
carBody.Background = new SolidColorBrush(Color);
Now its working fine.

How can i create N grid row ? In Xamarin/C#

I have a project. I have a table. ( Made from grid ) And i have a entry/Textbox. I need make like customer will write number to entry ( Lets call that number "n" ). Then i need add n row inside of my table made from grid. How can i do that ?
Its my codes for make grid table.
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Absolute)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Star)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Absolute)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Star)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Absolute)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Star)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Absolute)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Star)
});
gr.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Absolute)
});
gr.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Absolute)
});
gr.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Star)
});
gr.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Absolute)
});
gr.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Star)
});
gr.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Absolute)
});
var backgroundbox = new BoxView
{
Color = System.Drawing.Color.FromArgb(-32513)
};
gr.Children.Add(backgroundbox, 0, 1);
Grid.SetColumnSpan(backgroundbox, 5);
var ustyatay = new BoxView { Color = System.Drawing.Color.Gray };
gr.Children.Add(ustyatay, 0, 0);
Grid.SetColumnSpan(ustyatay, 5);
var yatay2 = new BoxView { Color = System.Drawing.Color.Gray };
gr.Children.Add(yatay2, 0, 2);
Grid.SetColumnSpan(yatay2, 5);
var yatay3 = new BoxView { Color = Xamarin.Forms.Color.Gray };
gr.Children.Add(yatay3, 0, 4);
Grid.SetColumnSpan(yatay3, 5);
var yatay4 = new BoxView { Color = Xamarin.Forms.Color.Gray };
gr.Children.Add(yatay4, 0, 6);
Grid.SetColumnSpan(yatay4, 5);
var soldik = new BoxView { Color = System.Drawing.Color.Gray };
gr.Children.Add(soldik, 0, 0);
Grid.SetRowSpan(soldik, 7);
var ortadik = new BoxView { Color = Xamarin.Forms.Color.Gray };
gr.Children.Add(ortadik, 2, 0);
Grid.SetRowSpan(ortadik, 7);
var sagdik = new BoxView { Color = System.Drawing.Color.Gray };
gr.Children.Add(sagdik, 4, 0);
Grid.SetRowSpan(sagdik, 7);
gr.Children.Add(new Label
{
Text = "Customer Name",
FontAttributes = FontAttributes.Bold,
TextColor = System.Drawing.Color.Yellow,
FontSize = 16,
Padding=new Thickness(10,10)
}, 1, 1); ;
gr.Children.Add(new Label
{
Text = "T.Type Name",
FontAttributes = FontAttributes.Bold,
TextColor= Xamarin.Forms.Color.Yellow,
FontSize=16,
Padding = new Thickness(10, 10)
}, 3, 1);
I made lines as grid column,row too. I think i made it wrong. When i add n row i need change rowspan too. Idk how can i make that project. Can you guys help me please ? I need learn : How can i add rows with entry , how can i add boxview and rowspan for new row (For make line) ? Thanks for help guys!
That photo for what should i do with my hand drawing : https://prnt.sc/10jxdhn
I can slove the problem by using Data binding.
First, edit your .xaml file like this:
<Entry Text="{Binding N}"></Entry>
<Button Text="Create" Command ="{Binding CreateCommand}"></Button>
<ListView ItemsSource="{Binding Rows}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding}"></Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Next create a ViewModel, I call it Page1ViewModel.cs.
In .xaml.cs file, add the binding context to Page1ViewModel in the constructor
BindingContext = new Page1ViewModel();
In Page1ViewModel.cs:
class Page1ViewModel : INotifyPropertyChanged
{
private int n;
private List<string> rows;
public List<string> Rows
{
get => rows;
set
{
rows = value;
OnPropertyChanged();
}
}
public int N
{
get => n;
set
{
n = value;
OnPropertyChanged();
}
}
public Command CreateCommand { get; }
public Page1ViewModel()
{
Rows = new List<string>();
CreateCommand = new Command(Create);
}
private void Create()
{
List <string> tmp = new List<string>();
for (int i = 0; i < n; i++)
{
tmp.Add("Row" + i);
}
Rows = tmp;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Good luck!

Print all data in the DataGrid in WPF

I am working on WPF application. I have data in the DataGrid which I have to print all the data present in it. I tried like this...
publicMainWindow()
{
InitializeComponent();
DataTabledt = newDataTable();
dt.Columns.Add("S.No");
dt.Columns.Add("Name");
dt.Columns.Add("Father's Name");
dt.Columns.Add("D-O-B");
dt.Columns.Add("Qualification");
dt.Columns.Add("Gender");
dt.Columns.Add("SSC %");
dt.Columns.Add("+2 %");
dt.Columns.Add("Graduation %");
dt.Columns.Add("Work Experience");
dt.Columns.Add("Company");
object[] rowValues = {"01","Gopi","Ravi","31","Degree","M", "88","85", "80","2 Years","Blah Blah"};
dt.Rows.Add(rowValues);
dt.AcceptChanges();
myGrid.DataContext = dt.DefaultView;
}
privatevoidPrint_Click(object sender, RoutedEventArgs e)
{
PrintDialogprintDlg = newPrintDialog();
if ((bool)printDlg.ShowDialog().GetValueOrDefault())
{
Sizepagesize = newSize(printDlg.PrintableAreaWidth,printDlg.PrintableAreaHeight);
myGrid.Measure(pagesize);
myGrid.Arrange(newRect(5, 5, pagesize.Width, pagesize.Height));
printDlg.PrintVisual(myGrid, "Personal Information");
}
}
when I click on print button it is printing only the data which we can see as below
But in my case it is not printing work experience and company columns. How can I Print all the fields. Please help me out
EDIT: I think FlowDocument is used, but suppose I have 50 rows I cannot use FlowDocument. How can I Print in this case.
I have done code recently. It is tested code.It will print every datagrid with all records.It is easy and simple code.You would add a class. If you want to decorate a datagrid then go to PrintDG class then decorate it according to your own requirement.
Follow these steps.
Step1: Add these references on top.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
public class PrintDG
{
public void printDG(DataGrid dataGrid, string title)
{
PrintDialog printDialog = new PrintDialog();
if (printDialog.ShowDialog() == true)
{
FlowDocument fd = new FlowDocument();
Paragraph p = new Paragraph(new Run(title));
p.FontStyle = dataGrid.FontStyle;
p.FontFamily = dataGrid.FontFamily;
p.FontSize = 18;
fd.Blocks.Add(p);
Table table = new Table();
TableRowGroup tableRowGroup = new TableRowGroup();
TableRow r = new TableRow();
fd.PageWidth = printDialog.PrintableAreaWidth;
fd.PageHeight = printDialog.PrintableAreaHeight;
fd.BringIntoView();
fd.TextAlignment = TextAlignment.Center;
fd.ColumnWidth = 500;
table.CellSpacing = 0;
var headerList = dataGrid.Columns.Select(e => e.Header.ToString()).ToList();
List<dynamic> bindList = new List<dynamic>();
for (int j = 0; j < headerList.Count; j++)
{
r.Cells.Add(new TableCell(new Paragraph(new Run(headerList[j]))));
r.Cells[j].ColumnSpan = 4;
r.Cells[j].Padding = new Thickness(4);
r.Cells[j].BorderBrush = Brushes.Black;
r.Cells[j].FontWeight = FontWeights.Bold;
r.Cells[j].Background = Brushes.DarkGray;
r.Cells[j].Foreground = Brushes.White;
r.Cells[j].BorderThickness = new Thickness(1, 1, 1, 1);
var binding = (dataGrid.Columns[j] as DataGridBoundColumn).Binding as Binding;
bindList.Add(binding.Path.Path);
}
tableRowGroup.Rows.Add(r);
table.RowGroups.Add(tableRowGroup);
for (int i = 0; i < dataGrid.Items.Count; i++)
{
dynamic row;
if (dataGrid.ItemsSource.ToString().ToLower() == "system.data.linqdataview")
{ row = (DataRowView)dataGrid.Items.GetItemAt(i); }
else
{
row = (BalanceClient)dataGrid.Items.GetItemAt(i);
}
table.BorderBrush = Brushes.Gray;
table.BorderThickness = new Thickness(1, 1, 0, 0);
table.FontStyle = dataGrid.FontStyle;
table.FontFamily = dataGrid.FontFamily;
table.FontSize = 13;
tableRowGroup = new TableRowGroup();
r = new TableRow();
for (int j = 0; j < row.Row.ItemArray.Count(); j++)
{
if (dataGrid.ItemsSource.ToString().ToLower() == "system.data.linqdataview")
{
r.Cells.Add(new TableCell(new Paragraph(new Run(row.Row.ItemArray[j].ToString()))));
}
else
{
r.Cells.Add(new TableCell(new Paragraph(new Run(row.GetType().GetProperty(bindList[j]).GetValue(row, null)))));
}
r.Cells[j].ColumnSpan = 4;
r.Cells[j].Padding = new Thickness(4);
r.Cells[j].BorderBrush = Brushes.DarkGray;
r.Cells[j].BorderThickness = new Thickness(0, 0, 1, 1);
}
tableRowGroup.Rows.Add(r);
table.RowGroups.Add(tableRowGroup);
}
fd.Blocks.Add(table);
printDialog.PrintDocument(((IDocumentPaginatorSource)fd).DocumentPaginator, "");
}
}
}
Step2: Then go to print button click event and create object of PrintDG class then call printDG pass to It two parameters datagridname and title.
Like :
private void print_button_Click(object sender, RoutedEventArgs e)
{
PrintDG print = new PrintDG();
print.printDG(datagridName, "Title");
}
If any error occurs during execution tell me and I will solve It.This is running code only, you need copy and paste.
Edited:
I declared row as dynamic. The dynamic keyword decides at run time which type to instantiate, either DataTable or another.
I work with This :
// Author : Kadi Okba
public class WpfPrinting
{
public const double cm = 37;
public double Margin = 0.5 * cm;
public double PageWidth = 21 * cm;
public double PageHeight = 29 * cm;
public double RowHeight = 0.7 * cm;
public bool PageNumberVisibility = true;
public bool DateVisibility = true;
public double FontSize = 14;
public double HeaderFontSize = 14;
public bool IsBold = false;
public void PrintDataGrid(FrameworkElement header, DataGrid grid, FrameworkElement footer, PrintDialog printDialog)
{
if (header == null) { header = new FrameworkElement(); header.Width = 1; header.Height = 1; }
if (footer == null) { footer = new FrameworkElement(); footer.Width = 1; footer.Height = 1; }
if (grid == null) return;
Size pageSize = new Size(PageWidth, PageHeight);
FixedDocument fixedDoc = new FixedDocument();
fixedDoc.DocumentPaginator.PageSize = pageSize;
double GridActualWidth = grid.ActualWidth == 0 ? grid.Width : grid.ActualWidth;
double PageWidthWithMargin = pageSize.Width - Margin * 2;
double PageHeightWithMargin = pageSize.Height - Margin * 2;
// scale the header
double headerScale = (header?.Width ?? 0) / PageWidthWithMargin;
double headerWidth = PageWidthWithMargin;
double headerHeight = (header?.Height ?? 0) * headerScale;
header.Height = headerHeight;
header.Width = headerWidth;
// scale the footer
double footerScale = (footer?.Width ?? 0) / PageWidthWithMargin;
double footerWidth = PageWidthWithMargin;
double footerHeight = (footer?.Height ?? 0) * footerScale;
footer.Height = footerHeight;
footer.Width = footerWidth;
int pageNumber = 1;
string Now = DateTime.Now.ToShortDateString();
//add the header
FixedPage fixedPage = new FixedPage();
fixedPage.Background = Brushes.White;
fixedPage.Width = pageSize.Width;
fixedPage.Height = pageSize.Height;
FixedPage.SetTop(header, Margin);
FixedPage.SetLeft(header, Margin);
fixedPage.Children.Add(header);
// its like cursor for current page Height to start add grid rows
double CurrentPageHeight = headerHeight + 1 * cm;
int lastRowIndex = 0;
bool IsFooterAdded = false;
for (;;)
{
int AvaliableRowNumber;
var SpaceNeededForRestRows = (CurrentPageHeight + (grid.Items.Count - lastRowIndex) * RowHeight);
//To avoid printing the footer in a separate page
if (SpaceNeededForRestRows > (pageSize.Height - footerHeight - Margin) && (SpaceNeededForRestRows < (pageSize.Height - Margin)))
AvaliableRowNumber = (int)((pageSize.Height - CurrentPageHeight - Margin - footerHeight) / RowHeight);
// calc the Avaliable Row acording to CurrentPageHeight
else AvaliableRowNumber = (int)((pageSize.Height - CurrentPageHeight - Margin) / RowHeight);
// create new page except first page cause we created it prev
if (pageNumber > 1)
{
fixedPage = new FixedPage();
fixedPage.Background = Brushes.White;
fixedPage.Width = pageSize.Width;
fixedPage.Height = pageSize.Height;
}
// create new data grid with columns width and binding
DataGrid gridToAdd;
gridToAdd = GetDataGrid(grid, GridActualWidth, PageWidthWithMargin);
FixedPage.SetTop(gridToAdd, CurrentPageHeight); // top margin
FixedPage.SetLeft(gridToAdd, Margin); // left margin
// add the avaliable rows to the cuurent grid
for (int i = lastRowIndex; i < grid.Items.Count && i < AvaliableRowNumber + lastRowIndex; i++)
{
gridToAdd.Items.Add(grid.Items[i]);
}
lastRowIndex += gridToAdd.Items.Count + 1;
// add date
TextBlock dateText = new TextBlock();
if (DateVisibility) dateText.Visibility = Visibility.Visible;
else dateText.Visibility = Visibility.Hidden;
dateText.Text = Now;
// add page number
TextBlock PageNumberText = new TextBlock();
if (PageNumberVisibility) PageNumberText.Visibility = Visibility.Visible;
else PageNumberText.Visibility = Visibility.Hidden;
PageNumberText.Text = "Page : " + pageNumber;
FixedPage.SetTop(dateText, PageHeightWithMargin);
FixedPage.SetLeft(dateText, Margin);
FixedPage.SetTop(PageNumberText, PageHeightWithMargin);
FixedPage.SetLeft(PageNumberText, PageWidthWithMargin - PageNumberText.Text.Length * 10);
fixedPage.Children.Add(gridToAdd);
fixedPage.Children.Add(dateText);
fixedPage.Children.Add(PageNumberText);
// calc Current Page Height to know the rest Height of this page
CurrentPageHeight += gridToAdd.Items.Count * RowHeight;
// all grid rows added
if (lastRowIndex >= grid.Items.Count)
{
// if footer have space it will be added to the same page
if (footerHeight < (PageHeightWithMargin - CurrentPageHeight))
{
FixedPage.SetTop(footer, CurrentPageHeight + Margin);
FixedPage.SetLeft(footer, Margin);
fixedPage.Children.Add(footer);
IsFooterAdded = true;
}
}
fixedPage.Measure(pageSize);
fixedPage.Arrange(new Rect(new Point(), pageSize));
fixedPage.UpdateLayout();
PageContent pageContent = new PageContent();
((IAddChild)pageContent).AddChild(fixedPage);
fixedDoc.Pages.Add(pageContent);
pageNumber++;
// go to start position : New page Top
CurrentPageHeight = Margin;
// this mean that lastRowIndex >= grid.Items.Count and the footer dont have enough space
if (lastRowIndex >= grid.Items.Count && !IsFooterAdded)
{
FixedPage ffixedPage = new FixedPage();
ffixedPage.Background = Brushes.White;
ffixedPage.Width = pageSize.Width;
ffixedPage.Height = pageSize.Height;
FixedPage.SetTop(footer, Margin);
FixedPage.SetLeft(footer, Margin);
TextBlock fdateText = new TextBlock();
if (DateVisibility) fdateText.Visibility = Visibility.Visible;
else fdateText.Visibility = Visibility.Hidden;
dateText.Text = Now;
TextBlock fPageNumberText = new TextBlock();
if (PageNumberVisibility) fPageNumberText.Visibility = Visibility.Visible;
else fPageNumberText.Visibility = Visibility.Hidden;
fPageNumberText.Text = "Page : " + pageNumber;
FixedPage.SetTop(fdateText, PageHeightWithMargin);
FixedPage.SetLeft(fdateText, Margin);
FixedPage.SetTop(fPageNumberText, PageHeightWithMargin);
FixedPage.SetLeft(fPageNumberText, PageWidthWithMargin - PageNumberText.ActualWidth);
ffixedPage.Children.Add(footer);
ffixedPage.Children.Add(fdateText);
ffixedPage.Children.Add(fPageNumberText);
ffixedPage.Measure(pageSize);
ffixedPage.Arrange(new Rect(new Point(), pageSize));
ffixedPage.UpdateLayout();
PageContent fpageContent = new PageContent();
((IAddChild)fpageContent).AddChild(ffixedPage);
fixedDoc.Pages.Add(fpageContent);
IsFooterAdded = true;
}
if (IsFooterAdded)
{
break;
}
}
PrintFixedDocument(fixedDoc, printDialog);
}
private DataGrid GetDataGrid(DataGrid grid, double GridActualWidth, double PageWidthWithMargin)
{
DataGrid printed = new DataGrid();
// styling the grid
Style rowStyle = new Style(typeof(DataGridRow));
rowStyle.Setters.Add(new Setter(Control.BackgroundProperty, Brushes.White));
rowStyle.Setters.Add(new Setter(Control.FontSizeProperty, FontSize));
if (IsBold) rowStyle.Setters.Add(new Setter(Control.FontWeightProperty, FontWeights.Bold));
rowStyle.Setters.Add(new Setter(Control.HeightProperty, RowHeight));
Style columnStyle = new Style(typeof(DataGridColumnHeader));
columnStyle.Setters.Add(new Setter(Control.FontSizeProperty, HeaderFontSize));
columnStyle.Setters.Add(new Setter(Control.HorizontalContentAlignmentProperty, HorizontalAlignment.Center));
columnStyle.Setters.Add(new Setter(Control.BorderThicknessProperty, new Thickness(0, 0.5, 0, 1.5)));
columnStyle.Setters.Add(new Setter(Control.BackgroundProperty, Brushes.White));
columnStyle.Setters.Add(new Setter(Control.BorderBrushProperty, Brushes.Black));
columnStyle.Setters.Add(new Setter(Control.FontWeightProperty, FontWeights.SemiBold));
printed.RowStyle = rowStyle;
printed.VerticalGridLinesBrush = Brushes.Black;
printed.HorizontalGridLinesBrush = Brushes.Black;
printed.FontFamily = new FontFamily("Arial");
printed.RowBackground = Brushes.White;
printed.Background = Brushes.White;
printed.Foreground = Brushes.Black;
// get the columns of grid
foreach (var column in grid.Columns)
{
if (column.Visibility != Visibility.Visible) continue;
DataGridTextColumn textColumn = new DataGridTextColumn();
textColumn.HeaderStyle = columnStyle;
textColumn.Header = column.Header;
textColumn.Width = column.ActualWidth / GridActualWidth * PageWidthWithMargin;
textColumn.Binding = ((DataGridTextColumn)column).Binding;
printed.Columns.Add(textColumn);
}
printed.BorderBrush = Brushes.Black;
return printed;
}
public void PrintFixedDocument(FixedDocument fixedDoc, PrintDialog printDialog)
{
XpsDocumentWriter writer = PrintQueue.CreateXpsDocumentWriter(printDialog.PrintQueue);
writer.Write(fixedDoc, printDialog.PrintTicket);
}
}

WPF Adding Image as Content to Button doesn't work

I am trying to create image 15-puzzle game, where you have to combine the image by sliding the squares.
Almost everything works correctly, except that instead of showing the image inside a button it shows it as a text "System.Drawing.Image".
Here is my MainWindow.xaml.cs code:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Collections;
using static System.Math;
using System.Collections.Generic;
using System.Drawing;
using Image = System.Drawing.Image;
using Brushes = System.Windows.Media.Brushes;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace Quizz
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
//Array of buttons
private static readonly List<Button> Buttons = new List<Button>(15);
// Position of an empty space
private static int _xPos;
private static int _yPos;
public MainWindow()
{
InitializeComponent();
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
for (var i = 0; i < 15; i++)
{
Buttons.Add(new Button() { Background = Brushes.AliceBlue });
}
_xPos = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), System.Globalization.NumberStyles.HexNumber)).Next(3);
_yPos = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), System.Globalization.NumberStyles.HexNumber)).Next(3);
CreateDynamicWpfGrid();
}
private void CreateDynamicWpfGrid()
{
// Create the Grid
var dynamicGrid = new Grid { ShowGridLines = true };
// Create Columns
var gridCol1 = new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) };
var gridCol2 = new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) };
var gridCol3 = new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) };
var gridCol4 = new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) };
dynamicGrid.ColumnDefinitions.Add(gridCol1);
dynamicGrid.ColumnDefinitions.Add(gridCol2);
dynamicGrid.ColumnDefinitions.Add(gridCol3);
dynamicGrid.ColumnDefinitions.Add(gridCol4);
// Create Rows
var gridRow1 = new RowDefinition { Height = new GridLength(1, GridUnitType.Star) };
var gridRow2 = new RowDefinition { Height = new GridLength(1, GridUnitType.Star) };
var gridRow3 = new RowDefinition { Height = new GridLength(1, GridUnitType.Star) };
var gridRow4 = new RowDefinition { Height = new GridLength(1, GridUnitType.Star) };
dynamicGrid.RowDefinitions.Add(gridRow1);
dynamicGrid.RowDefinitions.Add(gridRow2);
dynamicGrid.RowDefinitions.Add(gridRow3);
dynamicGrid.RowDefinitions.Add(gridRow4);
// Bind Buttons and Grid Cells
int j = 0;
var imgList = Randomizer();
for (var i = 0; i < 16; i++)
{
if (i % 4 != _xPos || _yPos != i / 4)
{
//Add image in a button
Buttons[j].Content = imgList[j];
Buttons[j].Click += Button_Click;
Grid.SetColumn(Buttons[j], i%4);
Grid.SetRow(Buttons[j], i/4);
dynamicGrid.Children.Add(Buttons[j]);
j++;
}
}
// Display grid into a Window
RootWindow.Content = dynamicGrid;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = (Button)sender;
var x = Grid.GetColumn(button);
var y = Grid.GetRow(button);
if ((Abs(_xPos - x) != 1 || Abs(_yPos - y) != 0) && (Abs(_yPos - y) != 1 || Abs(_xPos - x) != 0)) return;
Grid.SetColumn(button, _xPos);
Grid.SetRow(button, _yPos);
_xPos = x;
_yPos = y;
}
private List<Image> Randomizer()
{
var imageList = CropImage();
var randomImageList = new List<Image>(15);
for (var i = 0; i < 15; i++)
{
var pos = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), System.Globalization.NumberStyles.HexNumber)).Next(imageList.Count);
randomImageList.Add(imageList[pos]);
imageList.RemoveAt(pos);
}
return randomImageList;
}
private Bitmap ResizeImage(Image image)
{
var destRect = new Rectangle(0, 0, (int)RootWindow.Width ,(int) RootWindow.Height );
var destImage = new Bitmap((int)RootWindow.Width, (int)RootWindow.Height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
private List<Image> CropImage()
{
var imgList = new List<Image>(16);
var img = (Image)ResizeImage(Image.FromFile(#"D:\Documents\Шаг\Программы WPF\Quizz\Quizz\Resources\Image.jpeg"));
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
var index = i * 4 + j;
imgList.Add(new Bitmap(80, 80));
var graphics = Graphics.FromImage(imgList[index]);
graphics.DrawImage(img, new Rectangle(0, 0, 80, 80), new Rectangle(i * 80, j * 80, 80, 80), GraphicsUnit.Pixel);
graphics.Dispose();
}
}
imgList.RemoveAt(imgList.Count - 1);
return imgList;
}
}
}
Here is my MainWindow.xaml code:
<Window x:Class="Quizz.MainWindow"
Title="Пятнашки" Icon="pack://application:,,,/Quizz;component/resources/Icon.ico"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="320" Width="320"
Name="RootWindow" ResizeMode="NoResize"
Loaded="MainWindow_Loaded">
</Window>
What am I doing wrong??
Here is what I did to get this to work.
I created a list of StackPanels similar to your button list.
private static readonly List<StackPanel> StackPanels = new List<StackPanel>(15);
then populated the list like you did the buttons..
private static readonly List<StackPanel> StackPanels = new List<StackPanel>(15);
Then Here is the for loop with the fix in the CreateDynamicWPFGrid method. Added the Stack panel to the content and added the Image to the stack panel after converting it to a Control.Image.
// Bind Buttons and Grid Cells
int j = 0;
var imgList = Randomizer();
for (var i = 0; i < 16; i++)
{
if (i % 4 != _xPos || _yPos != i / 4)
{
//Add image in a button
var bitmapImage = new BitmapImage();
var bitmap = imgList[j];
using (var memoryStream = new MemoryStream())
{
bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Bmp);
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = memoryStream;
bitmapImage.EndInit();
}
var image = new System.Windows.Controls.Image
{
Source = bitmapImage,
Stretch = Stretch.None
};
var currentstack = StackPanels[j];
currentstack.Orientation = Orientation.Horizontal;
currentstack.Children.Add(image);
Buttons[j].Content = currentstack;
Buttons[j].Click += Button_Click;
Grid.SetColumn(Buttons[j], i % 4);
Grid.SetRow(Buttons[j], i / 4);
dynamicGrid.Children.Add(Buttons[j]);
j++;
}
}

Categories

Resources