Unblock row editing on WPF DataGrid - wpf

I have validation in DataGrid. I am copying and trying to paste multiple rows. But if there is a validation error in one of the rows on insertion, the validation will will be called in and disable editing of the other rows, therefore next rows will not be inserted.
My ValidationRule:
public class MyValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
MyModel myModel = (value as BindingGroup).Items[0] as MyModel ;
if (myModel.Top > myModel.Bottom)
{
return new ValidationResult(false, "Error!");
}
return new ValidationResult(true,null);
}
}
XAML:
<DataGrid.RowValidationRules>
<MyValidationRule ValidationStep="UpdatedValue"/>
<DataGrid.RowValidationRules>
The paste code:
protected virtual void OnExecutedPaste(object target, ExecutedRoutedEventArgs args)
{
if (ExecutePasteEvent != null)
{
ExecutePasteEvent(target, args);
if (args.Handled)
{
return;
}
}
List<string[]> clipboardData = Clipboard
Helper2.ParseClipboardData();
int minRowIndex = Items.Count;
int maxRowIndex = Items.Count;
int minColumn = 0;
if (SelectedCells.Any())
{
minRowIndex = SelectedCells.Min(g=> Items.IndexOf(g.Item));
maxRowIndex = Items.Count;
minColumn = SelectedCells.Min(g=> g.Column.DisplayIndex);
}
int minColumnDisplayIndex = (SelectionUnit != DataGridSelectionUnit.FullRow) ? minColumn : 0;
int maxColumnDisplayIndex = Columns.Count - 1;
int rowDataIndex = 0;
List<Tuple<int, int>> cellsToSelect = new List<Tuple<int, int>>();
for (int i = minRowIndex; i <= maxRowIndex && rowDataIndex < clipboardData.Count; i++, rowDataIndex++)
{
if (i == maxRowIndex)
{
if (!CanUserPasteToNewRows)
continue;
ICollectionView cv = CollectionViewSource.GetDefaultView(Items);
IEditableCollectionView iecv = cv as IEditableCollectionView;
if (iecv != null)
{
if (minRowIndex + clipboardData.Count > Items.Count)
{
iecv.AddNew();
if (rowDataIndex < clipboardData.Count)
{
maxRowIndex = Items.Count;
}
}
}
}
if (i < Items.Count)
{
CurrentItem = Items[i];
BeginEditCommand.Execute(null, this);
int clipboardColumnIndex = 0;
for (int j = minColumnDisplayIndex; clipboardColumnIndex < clipboardData[rowDataIndex].Length; j++, clipboardColumnIndex++)
{
DataGridColumn column = null;
foreach (DataGridColumn columnIter in this.Columns)
{
if (columnIter.DisplayIndex == j)
{
column = columnIter;
break;
}
}
column?.OnPastingCellClipboardContent(Items[i], clipboardData[rowDataIndex][clipboardColumnIndex]);
cellsToSelect.Add(new Tuple<int, int>(i, j));
}
CommitEditCommand.Execute(this, this);
}
}
UnselectAll();
UnselectAllCells();
if (Items.Count < 1)
return;
CurrentItem = Items[minRowIndex];
if (SelectionUnit == DataGridSelectionUnit.FullRow)
{
SelectedItem = Items[minRowIndex];
}
else if (SelectionUnit == DataGridSelectionUnit.CellOrRowHeader || SelectionUnit == DataGridSelectionUnit.Cell)
{
foreach(var c in cellsToSelect)
{
if(Columns.Count < c.Item1 && Columns.Count < c.Item2)
SelectedCells.Add(new DataGridCellInfo(Items[c.Item1], Columns[c.Item2]));
}
}
}
And ClipboardHelper.ParseClipboardData(); will return a list of strings for example: {"row1", "value1", "value2"},{"row2", "value1", "value2"}.
How to paste all copied rows?
And I need to allow editing of all rows with errors, and not the last one.

Related

WPF list modification during iteration?

I'm trying to make a very simple game where the yellow ball bouncing back and fourth. If it collides with one of the moving blue squares, the square is supposed to disappear and a new one should appear (always 3 in the window) elsewhere. When my code reaches this part, all 3 squares disappear (then reappears as intended it is not a problem) and I just cant figure out why. It would be a huge help if somebody could run over my methods responsible for the problem. Thank you in advance.
So my timer_Tick method, responsible for every frame:
void timer_Tick(object sender, EventArgs e)
{
logic.MoveBall();
if (model.Enemy.Count<3)
{
logic.AddEnemy();
}
int iii = 0;
foreach (MyShape enemy in model.Enemy) //the whole thing from here is me trying to solve list modification during iteration
{
if (logic.MoveEnemy(enemy) == -1)
{
logic.MoveEnemy(enemy);
}
else iii = logic.MoveEnemy(enemy);
}
if (iii > -1)
{
for (int j = model.Enemy.Count - 1; j >= 0; j--)
{
if (j == model.Enemy.Count - iii)
{
model.Enemy.RemoveAt(j);
}
}
}
}
MoveEnemy: I try to decide whether there is collusion and if yes, then try to remove the given shape object (blue square). Because This whole method is in a foreach, I just save the removable element and forward it to timer_Tick
public int MoveEnemy(MyShape shape)
{
int i = 0;
int ii = -1;
if ((shape.Area.IntersectsWith(model.Ball.Area)))
{
i = 0;
foreach (var e in model.Enemy)
{
i++;
if (shape == e)
{
ii = i;
}
}
}
shape.ChangeX(shape.Dx);
shape.ChangeY(shape.Dy);
bool coll = false;
foreach (var e in model.Enemy)
{
if ((e.Area.IntersectsWith(shape.Area)) && (shape != e))
{
coll = true;
}
}
if (shape.Area.Left < 0 || shape.Area.Right > Config.Width-40 || coll)
{
shape.Dx = -shape.Dx;
}
if (shape.Area.Top < 0)
{
shape.Dy = -shape.Dy;
}
if (shape.Area.Bottom > Config.Height/2)
{
shape.Dy = -shape.Dy;
}
RefreshScreen?.Invoke(this, EventArgs.Empty);
return ii;
}
And finally AddEnemy:
public void AddEnemy()
{
rnd = new Random();
int r = rnd.Next(-300, 300);
model.Enemy.Add(new MyShape(Config.Width / 2+r, 0, 40, 40));
RefreshScreen?.Invoke(this, EventArgs.Empty);
}
List<T> (or IList and Enumerable) exposes some useful methods to compact code:
int itemIndex = list.IndexOf(item); // Gets the index of the item if found, otherwise returns -1
list.Remove(item); // Remove item if contained in collection
list.RemoveAll(item => item > 5); // Removes all items that satisfy a condition (replaces explicit iteration)
bool hasAnyMatch = list.Any(item => item > 5); // Returns true as soon as the first item satisfies the condition (replaces explicit iteration)
A simplified version, which should eliminate the flaw:
void timer_Tick(object sender, EventArgs e)
{
if (model.Enemy.Count < 3)
{
logic.AddEnemy();
}
logic.MoveBall();
model.Enemy.ForeEach(logic.MoveEnemy);
model.Enemy.RemoveAll(logic.IsCollidingWithBall);
}
public void AddEnemy()
{
rnd = new Random();
int r = rnd.Next(-300, 300);
model.Enemy.Add(new MyShape(Config.Width / 2 + r, 0, 40, 40));
RefreshScreen?.Invoke(this, EventArgs.Empty);
}
public bool IsCollidingWithBall(MyShape shape)
{
return shape.Area.IntersectsWith(model.Ball.Area);
}
public int MoveEnemy(MyShape shape)
{
shape.ChangeX(shape.Dx);
shape.ChangeY(shape.Dy);
bool hasCollision = model.Enemy.Any(enemy => enemy.Area.IntersectsWith(shape.Area)
&& enemy != shape);
if (hasCollision || shape.Area.Left < 0 || shape.Area.Right > Config.Width - 40)
{
shape.Dx = -shape.Dx;
}
if (shape.Area.Top < 0)
{
shape.Dy = -shape.Dy;
}
if (shape.Area.Bottom > Config.Height / 2)
{
shape.Dy = -shape.Dy;
}
RefreshScreen?.Invoke(this, EventArgs.Empty);
}

How to change DataGridCell value programatically

I have a DataGrid with some rows.Now I want change some cell style, eg:
|red| Hel |/red| |blue| lo |/blue| Everybody.
Here is my GetCell function.
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
var v = (Visual) VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
public static DataGridRow GetSelectedRow(this DataGrid grid)
{
return (DataGridRow) grid.ItemContainerGenerator.ContainerFromItem(grid.SelectedItem);
}
public static DataGridRow GetRow(this DataGrid grid, int index)
{
var row = (DataGridRow) grid.ItemContainerGenerator.ContainerFromIndex(index);
if (row != null) return row;
// May be virtualized, bring into view and try again.
grid.UpdateLayout();
grid.ScrollIntoView(grid.Items[index]);
row = (DataGridRow) grid.ItemContainerGenerator.ContainerFromIndex(index);
return row;
}
public static DataGridCell GetCell(this DataGrid grid, DataGridRow row, int column)
{
if (row == null) return null;
var presenter = GetVisualChild<DataGridCellsPresenter>(row);
if (presenter == null)
{
grid.ScrollIntoView(row, grid.Columns[column]);
presenter = GetVisualChild<DataGridCellsPresenter>(row);
}
var cell = (DataGridCell) presenter.ItemContainerGenerator.ContainerFromIndex(column);
if (cell == null)
{
grid.ScrollIntoView(row, grid.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
}
return cell;
}
public static DataGridCell GetCell(this DataGrid grid, int row, int column)
{
DataGridRow rowContainer = grid.GetRow(row);
return grid.GetCell(rowContainer, column);
}
When I set DataGridCell content with some value by grid.GetCell(1, 0).Content = "PpppPppp", and then scroll DataGrid, the value is gone!
Why?
Even the value jumps to another cell.So strange.
I want to set the cell with style, so not use the funtion about:
(this.dataGrid1.Items[0] as DataRowView)[0] = "new value";
But:
private void SetBlockStyle(TextBlock block, Dictionary<int, int> section)
{
Brush foreground = Brushes.Red;
int start = 0;
string text = block.Text;
block.Text = "";
foreach (int i in section.Keys)
{
if (text.Length <= i)
{
break;
}
block.Inlines.Add(text.Substring(start, i - start));
start = i;
block.Inlines.Add(new Run(text.Substring(i, section[i]))
{
Foreground = foreground,
FontWeight = FontWeights.Bold
});
start += section[i];
}
if (start < text.Length)
{
block.Inlines.Add(text.Substring(start, text.Length - start));
}
}
Can you give me some advice?

DataDriven testing with TestNG using Apache POI in Selenium WebDriver

I am new to TestNG framework. Please guide how to parameterise the test cases using Apache POI(Excel).
I have a code to read from second row from Excel.
public class spreadData {
private transient Collection data = null;
public spreadData(final InputStream excelInputStream) throws IOException {
this.data = loadFromSpreadsheet(excelInputStream);
}
public Collection getData() {
return data;
}
private Collection loadFromSpreadsheet(final InputStream excelFile)
throws IOException {
HSSFWorkbook workbook = new HSSFWorkbook(excelFile);
data = new ArrayList();
Sheet sheet = workbook.getSheetAt(0);
int numberOfColumns = countNonEmptyColumns(sheet);
List rows = new ArrayList();
List rowData = new ArrayList();
/*for (Row row : sheet) {
if (isEmpty(row)) {
break;
} else {
rowData.clear();
for (int column = 0; column < numberOfColumns; column++) {
Cell cell = row.getCell(column);
rowData.add(objectFrom(workbook, cell));
}
rows.add(rowData.toArray());
}
}*/
int rowStart = 1;
//int rowEnd = Math.max(1400, sheet.getLastRowNum());
for (int rowNum = rowStart; rowNum <= sheet.getLastRowNum(); rowNum++) {
//Row r = sheet.getRow(rowNum);
Row read = sheet.getRow(rowNum);
if (isEmpty(read)) {
break;
} else {
rowData.clear();
for (int column = 0; column < numberOfColumns; column++) {
Cell cell = read.getCell(column);
rowData.add(objectFrom(workbook, cell));
}
rows.add(rowData.toArray());
}
}
return rows;
}
private boolean isEmpty(final Row row) {
Cell firstCell = row.getCell(0);
boolean rowIsEmpty = (firstCell == null)
|| (firstCell.getCellType() == Cell.CELL_TYPE_BLANK);
return rowIsEmpty;
}
/**
* Count the number of columns, using the number of non-empty cells in the
* first row.
*/
private int countNonEmptyColumns(final Sheet sheet) {
Row firstRow = sheet.getRow(0);
return firstEmptyCellPosition(firstRow);
}
private int firstEmptyCellPosition(final Row cells) {
int columnCount = 0;
for (Cell cell : cells) {
if (cell.getCellType() == Cell.CELL_TYPE_BLANK) {
break;
}
columnCount++;
}
return columnCount;
}
private Object objectFrom(final HSSFWorkbook workbook, final Cell cell) {
Object cellValue = null;
if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
cellValue = cell.getRichStringCellValue().getString();
} else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
cellValue = getNumericCellValue(cell);
} else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
cellValue = cell.getBooleanCellValue();
} else if (cell.getCellType() ==Cell.CELL_TYPE_FORMULA) {
cellValue = evaluateCellFormula(workbook, cell);
}
return cellValue;
}
private Object getNumericCellValue(final Cell cell) {
Object cellValue;
if (DateUtil.isCellDateFormatted(cell)) {
cellValue = new Date(cell.getDateCellValue().getTime());
} else {
cellValue = cell.getNumericCellValue();
}
return cellValue;
}
private Object evaluateCellFormula(final HSSFWorkbook workbook, final Cell cell) {
FormulaEvaluator evaluator = workbook.getCreationHelper()
.createFormulaEvaluator();
CellValue cellValue = evaluator.evaluate(cell);
Object result = null;
if (cellValue.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
result = cellValue.getBooleanValue();
} else if (cellValue.getCellType() == Cell.CELL_TYPE_NUMERIC) {
result = cellValue.getNumberValue();
} else if (cellValue.getCellType() == Cell.CELL_TYPE_STRING) {
result = cellValue.getStringValue();
}
return result;
}
}
My question is how to parameterise the test cases using TestNG? means by using #DataProvider TestNG annotation.
Kindly help me with a sample code or explanation.
I'm not sure which set of data you want...but here's how a dataProvider works:
Say I have a test that takes a String and then an int like this:
#Test(dataProvider = "excelData")
public void executeTest(String name, int value){}
My data provider would look something like this:
#DataProvider(name = "excelData")
public Object[][] data(){
return new Object[][]{
{"Test",1},
{"More Testing",7},
{"Last Test",-5}}
}
The test will be run 3 times, with each row of the array is the set of data that is to be passed in. You will need to convert your excel data into such a format.
Note, you can also return an Iterator<Object[]> if you prefer.

WPF ICollectionView Filtering

I've written a code for filtering items in ComboBox:
My question is, how would you do that?
I think that this solution with reflection could be very slow..
ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
view.Filter += this.FilterPredicate;
private bool FilterPredicate(object value)
{
if (value == null)
return false;
if (String.IsNullOrEmpty(SearchedText))
return true;
int index = value.ToString().IndexOf(
SearchedText,
0,
StringComparison.InvariantCultureIgnoreCase);
if ( index > -1) return true;
return FindInProperties(new string[] { "Property1", "Property2" }, value, SearchedText);
}
private bool FindInProperties(string[] properties, object value, string txtToFind)
{
PropertyInfo info = null;
for (int i = 0; i < properties.Length; i++)
{
info = value.GetType().GetProperty(properties[i]);
if (info == null) continue;
object s = info.GetValue(value, null);
if (s == null) continue;
int index = s.ToString().IndexOf(
txtToFind,
0,
StringComparison.InvariantCultureIgnoreCase);
if (index > -1) return true;
}
return false;
}
Why not just this:
ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
IEqualityComparer<String> comparer = StringComparer.InvariantCultureIgnoreCase;
view.Filter = o => {
Person p = o as Person;
return p.FirstName.Contains(SearchedText, comparer)
|| p.LastName.Contains(SearchedText, comparer);
}
Do you need to search properties dynamically?

Control for tags with auto-completion in Winforms?

I am seeking a WinForm control that would provide an autocomplete behavior for multiple space-separated - exactly ala del.icio.us (or stackoverflow.com for that matter).
Does anyone knows how to do that within a .NET 2.0 WinForm application?
ComboBox can autocomplete, but only one word at a time.
If you want to have each word separately autocompleted, you have to write your own.
I already did, hope it's not too long. It's not 100% exactly what you want, this was used for autocompleting in email client when typing in email adress.
/// <summary>
/// Extended TextBox with smart auto-completion
/// </summary>
public class TextBoxAC: TextBox
{
private List<string> completions = new List<string>();
private List<string> completionsLow = new List<string>();
private bool autocompleting = false;
private bool acDisabled = true;
private List<string> possibleCompletions = new List<string>();
private int currentCompletion = 0;
/// <summary>
/// Default constructor
/// </summary>
public TextBoxAC()
{
this.TextChanged += new EventHandler(TextBoxAC_TextChanged);
this.KeyPress += new KeyPressEventHandler(TextBoxAC_KeyPress);
this.KeyDown += new KeyEventHandler(TextBoxAC_KeyDown);
this.TabStop = true;
}
/// <summary>
/// Sets autocompletion data, list of possible strings
/// </summary>
/// <param name="words">Completion words</param>
/// <param name="wordsLow">Completion words in lowerCase</param>
public void SetAutoCompletion(List<string> words, List<string> wordsLow)
{
if (words == null || words.Count < 1) { return; }
this.completions = words;
this.completionsLow = wordsLow;
this.TabStop = false;
}
private void TextBoxAC_TextChanged(object sender, EventArgs e)
{
if (this.autocompleting || this.acDisabled) { return; }
string text = this.Text;
if (text.Length != this.SelectionStart) { return; }
int pos = this.SelectionStart;
string userPrefix = text.Substring(0, pos);
int commaPos = userPrefix.LastIndexOf(",");
if (commaPos == -1)
{
userPrefix = userPrefix.ToLower();
this.possibleCompletions.Clear();
int n = 0;
foreach (string s in this.completionsLow)
{
if (s.StartsWith(userPrefix))
{
this.possibleCompletions.Add(this.completions[n]);
}
n++;
}
if (this.possibleCompletions.Count < 1) { return; }
this.autocompleting = true;
this.Text = this.possibleCompletions[0];
this.autocompleting = false;
this.SelectionStart = pos;
this.SelectionLength = this.Text.Length - pos;
}
else
{
string curUs = userPrefix.Substring(commaPos + 1);
if (curUs.Trim().Length < 1) { return; }
string trimmed;
curUs = this.trimOut(curUs, out trimmed);
curUs = curUs.ToLower();
string oldUs = userPrefix.Substring(0, commaPos + 1);
this.possibleCompletions.Clear();
int n = 0;
foreach (string s in this.completionsLow)
{
if (s.StartsWith(curUs))
{
this.possibleCompletions.Add(this.completions[n]);
}
n++;
}
if (this.possibleCompletions.Count < 1) { return; }
this.autocompleting = true;
this.Text = oldUs + trimmed + this.possibleCompletions[0];
this.autocompleting = false;
this.SelectionStart = pos;
this.SelectionLength = this.Text.Length - pos + trimmed.Length;
}
this.currentCompletion = 0;
}
private void TextBoxAC_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete)
{
this.acDisabled = true;
}
if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)
{
if ((this.acDisabled) || (this.possibleCompletions.Count < 1))
{
return;
}
e.Handled = true;
if (this.possibleCompletions.Count < 2) { return; }
switch (e.KeyCode)
{
case Keys.Up:
this.currentCompletion--;
if (this.currentCompletion < 0)
{
this.currentCompletion = this.possibleCompletions.Count - 1;
}
break;
case Keys.Down:
this.currentCompletion++;
if (this.currentCompletion >= this.possibleCompletions.Count)
{
this.currentCompletion = 0;
}
break;
}
int pos = this.SelectionStart;
string userPrefix = this.Text.Substring(0, pos);
int commaPos = userPrefix.LastIndexOf(",");
if (commaPos == -1)
{
pos--;
userPrefix = this.Text.Substring(0, pos);
this.autocompleting = true;
this.Text = userPrefix + this.possibleCompletions[this.currentCompletion].Substring(userPrefix.Length);
this.autocompleting = false;
this.SelectionStart = pos + 1;
this.SelectionLength = this.Text.Length - pos;
}
else
{
string curUs = userPrefix.Substring(commaPos + 1);
if (curUs.Trim().Length < 1) { return; }
string trimmed;
curUs = this.trimOut(curUs, out trimmed);
curUs = curUs.ToLower();
string oldUs = userPrefix.Substring(0, commaPos + 1);
this.autocompleting = true;
this.Text = oldUs + trimmed + this.possibleCompletions[this.currentCompletion];
this.autocompleting = false;
this.SelectionStart = pos;
this.SelectionLength = this.Text.Length - pos + trimmed.Length;
}
}
}
private void TextBoxAC_KeyPress(object sender, KeyPressEventArgs e)
{
if (!Char.IsControl(e.KeyChar)) { this.acDisabled = false; }
}
private string trimOut(string toTrim, out string trim)
{
string ret = toTrim.TrimStart();
int pos = toTrim.IndexOf(ret);
trim = toTrim.Substring(0, pos);
return ret;
}
}

Resources