- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在从 csv 粘贴到 wpf 数据网格时遇到问题 - 我已遵循此处的建议
并且代码执行没有问题 - 但是,似乎所有新行都已创建,但只有第一行填充了数据。数据似乎不断被覆盖,以便剪贴板数据中的最后一项填充在第一行中,而所有其他行均为空白。我知道这一定是索引问题或其他问题,但我无法追踪它。
此外,当我查看网格可绑定(bind)集合中的对象时,它们都没有任何数据。该列的 OnPastingCellClipboardContent 中是否存在出现问题的内容(可能是数据转换)?
任何想法(请参阅下面的代码)
protected virtual void OnExecutedPaste(object sender, ExecutedRoutedEventArgs args)
{
// parse the clipboard data
List<string[]> rowData = ClipboardHelper.ParseClipboardData();
bool hasAddedNewRow = false;
// call OnPastingCellClipboardContent for each cell
int minRowIndex = Math.Max(Items.IndexOf(CurrentItem), 0);
int maxRowIndex = Items.Count - 1;
int minColumnDisplayIndex = (SelectionUnit != DataGridSelectionUnit.FullRow) ? Columns.IndexOf(CurrentColumn) : 0;
int maxColumnDisplayIndex = Columns.Count - 1;
int rowDataIndex = 0;
for (int i = minRowIndex; i <= maxRowIndex && rowDataIndex < rowData.Count; i++, rowDataIndex++)
{
if (CanUserAddRows && i == maxRowIndex)
{
// add a new row to be pasted to
ICollectionView cv = CollectionViewSource.GetDefaultView(Items);
IEditableCollectionView iecv = cv as IEditableCollectionView;
if (iecv != null)
{
hasAddedNewRow = true;
iecv.AddNew();
if (rowDataIndex + 1 < rowData.Count)
{
// still has more items to paste, update the maxRowIndex
maxRowIndex = Items.Count - 1;
}
}
}
else if (i == maxRowIndex)
{
continue;
}
int columnDataIndex = 0;
for (int j = minColumnDisplayIndex; j < maxColumnDisplayIndex && columnDataIndex < rowData[rowDataIndex].Length; j++, columnDataIndex++)
{
DataGridColumn column = ColumnFromDisplayIndex(j);
column.OnPastingCellClipboardContent(Items[i], rowData[rowDataIndex][columnDataIndex]);
}
}
}
最佳答案
谢谢
Vincent 的这篇文章非常好,但 KlausG 在其中添加了一些更正,这些更正也应该考虑与 FrameWork 4.0 一起使用。非常重要
注意:如果您无法添加行,请确保您的项目有一个默认构造函数。
更新于 2018-03-06(以支持 DataGrid 并由用户重新排序列)
更新于 2020 年 12 月 3 日(根据 Cesar Morigaki 解决方案修正和 Antonio Rodríguez 的消息)感谢双方!!!
使用
<myControl:CustomDataGrid ...
自定义数据网格
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace HQ.Wpf.Util.MyControl
{
public class CustomDataGrid : DataGrid
{
public event ExecutedRoutedEventHandler ExecutePasteEvent;
public event CanExecuteRoutedEventHandler CanExecutePasteEvent;
// ******************************************************************
static CustomDataGrid()
{
CommandManager.RegisterClassCommandBinding(
typeof(CustomDataGrid),
new CommandBinding(ApplicationCommands.Paste,
new ExecutedRoutedEventHandler(OnExecutedPasteInternal),
new CanExecuteRoutedEventHandler(OnCanExecutePasteInternal)));
}
// ******************************************************************
#region Clipboard Paste
// ******************************************************************
private static void OnCanExecutePasteInternal(object target, CanExecuteRoutedEventArgs args)
{
((CustomDataGrid)target).OnCanExecutePaste(target, args);
}
// ******************************************************************
/// <summary>
/// This virtual method is called when ApplicationCommands.Paste command query its state.
/// </summary>
/// <param name="args"></param>
protected virtual void OnCanExecutePaste(object target, CanExecuteRoutedEventArgs args)
{
if (CanExecutePasteEvent != null)
{
CanExecutePasteEvent(target, args);
if (args.Handled)
{
return;
}
}
args.CanExecute = CurrentCell != null;
args.Handled = true;
}
// ******************************************************************
private static void OnExecutedPasteInternal(object target, ExecutedRoutedEventArgs args)
{
((CustomDataGrid)target).OnExecutedPaste(target, args);
}
// ******************************************************************
/// <summary>
/// This virtual method is called when ApplicationCommands.Paste command is executed.
/// </summary>
/// <param name="target"></param>
/// <param name="args"></param>
protected virtual void OnExecutedPaste(object target, ExecutedRoutedEventArgs args)
{
if (ExecutePasteEvent != null)
{
ExecutePasteEvent(target, args);
if (args.Handled)
{
return;
}
}
// parse the clipboard data [row][column]
List<string[]> clipboardData = HQ.Util.General.Clipboard.ClipboardHelper2.ParseClipboardData();
bool hasAddedNewRow = false;
Debug.Print(">>> DataGrid Paste: >>>");
#if DEBUG
StringBuilder sb = new StringBuilder();
#endif
int minRowIndex = Items.IndexOf(CurrentItem);
int maxRowIndex = Items.Count - 1;
int startIndexOfDisplayCol = (SelectionUnit != DataGridSelectionUnit.FullRow) ? CurrentColumn.DisplayIndex : 0;
int clipboardRowIndex = 0;
for (int i = minRowIndex; i <= maxRowIndex && clipboardRowIndex < clipboardData.Count; i++, clipboardRowIndex++)
{
if (i < this.Items.Count)
{
CurrentItem = Items[i];
BeginEditCommand.Execute(null, this);
int clipboardColumnIndex = 0;
for (int j = startIndexOfDisplayCol; clipboardColumnIndex < clipboardData[clipboardRowIndex].Length; j++, clipboardColumnIndex++)
{
// DataGridColumn column = ColumnFromDisplayIndex(j);
DataGridColumn column = null;
foreach (DataGridColumn columnIter in this.Columns)
{
if (columnIter.DisplayIndex == j)
{
column = columnIter;
break;
}
}
column?.OnPastingCellClipboardContent(Items[i], clipboardData[clipboardRowIndex][clipboardColumnIndex]);
#if DEBUG
sb.AppendFormat("{0,-10}", clipboardData[clipboardRowIndex][clipboardColumnIndex]);
sb.Append(" - ");
#endif
}
CommitEditCommand.Execute(this, this);
if (i == maxRowIndex)
{
maxRowIndex++;
hasAddedNewRow = true;
}
}
Debug.Print(sb.ToString());
#if DEBUG
sb.Clear();
#endif
}
// update selection
if (hasAddedNewRow)
{
UnselectAll();
UnselectAllCells();
CurrentItem = Items[minRowIndex];
if (SelectionUnit == DataGridSelectionUnit.FullRow)
{
SelectedItem = Items[minRowIndex];
}
else if (SelectionUnit == DataGridSelectionUnit.CellOrRowHeader ||
SelectionUnit == DataGridSelectionUnit.Cell)
{
SelectedCells.Add(new DataGridCellInfo(Items[minRowIndex], Columns[startIndexOfDisplayCol]));
}
}
}
// ******************************************************************
/// <summary>
/// Whether the end-user can add new rows to the ItemsSource.
/// </summary>
public bool CanUserPasteToNewRows
{
get { return (bool)GetValue(CanUserPasteToNewRowsProperty); }
set { SetValue(CanUserPasteToNewRowsProperty, value); }
}
// ******************************************************************
/// <summary>
/// DependencyProperty for CanUserAddRows.
/// </summary>
public static readonly DependencyProperty CanUserPasteToNewRowsProperty =
DependencyProperty.Register("CanUserPasteToNewRows",
typeof(bool), typeof(CustomDataGrid),
new FrameworkPropertyMetadata(true, null, null));
// ******************************************************************
#endregion Clipboard Paste
private void SetGridToSupportManyEditEitherWhenValidationErrorExists()
{
this.Items.CurrentChanged += Items_CurrentChanged;
//Type DatagridType = this.GetType().BaseType;
//PropertyInfo HasCellValidationProperty = DatagridType.GetProperty("HasCellValidationError", BindingFlags.NonPublic | BindingFlags.Instance);
//HasCellValidationProperty.
}
void Items_CurrentChanged(object sender, EventArgs e)
{
//this.Items[0].
//throw new NotImplementedException();
}
// ******************************************************************
private void SetGridWritable()
{
Type DatagridType = this.GetType().BaseType;
PropertyInfo HasCellValidationProperty = DatagridType.GetProperty("HasCellValidationError", BindingFlags.NonPublic | BindingFlags.Instance);
if (HasCellValidationProperty != null)
{
HasCellValidationProperty.SetValue(this, false, null);
}
}
// ******************************************************************
public void SetGridWritableEx()
{
BindingFlags bindingFlags = BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo cellErrorInfo = this.GetType().BaseType.GetProperty("HasCellValidationError", bindingFlags);
PropertyInfo rowErrorInfo = this.GetType().BaseType.GetProperty("HasRowValidationError", bindingFlags);
cellErrorInfo.SetValue(this, false, null);
rowErrorInfo.SetValue(this, false, null);
}
// ******************************************************************
}
}
另外:剪贴板助手:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Windows;
using System.IO;
namespace HQ.Util.General.Clipboard
{
public static class ClipboardHelper
{
public delegate string[] ParseFormat(string value);
public static List<string[]> ParseClipboardData()
{
List<string[]> clipboardData = null;
object clipboardRawData = null;
ParseFormat parseFormat = null;
// get the data and set the parsing method based on the format
// currently works with CSV and Text DataFormats
IDataObject dataObj = System.Windows.Clipboard.GetDataObject();
if ((clipboardRawData = dataObj.GetData(DataFormats.CommaSeparatedValue)) != null)
{
parseFormat = ParseCsvFormat;
}
else if((clipboardRawData = dataObj.GetData(DataFormats.Text)) != null)
{
parseFormat = ParseTextFormat;
}
if (parseFormat != null)
{
string rawDataStr = clipboardRawData as string;
if (rawDataStr == null && clipboardRawData is MemoryStream)
{
// cannot convert to a string so try a MemoryStream
MemoryStream ms = clipboardRawData as MemoryStream;
StreamReader sr = new StreamReader(ms);
rawDataStr = sr.ReadToEnd();
}
Debug.Assert(rawDataStr != null, string.Format("clipboardRawData: {0}, could not be converted to a string or memorystream.", clipboardRawData));
string[] rows = rawDataStr.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
if (rows != null && rows.Length > 0)
{
clipboardData = new List<string[]>();
foreach (string row in rows)
{
clipboardData.Add(parseFormat(row));
}
}
else
{
Debug.WriteLine("unable to parse row data. possibly null or contains zero rows.");
}
}
return clipboardData;
}
public static string[] ParseCsvFormat(string value)
{
return ParseCsvOrTextFormat(value, true);
}
public static string[] ParseTextFormat(string value)
{
return ParseCsvOrTextFormat(value, false);
}
private static string[] ParseCsvOrTextFormat(string value, bool isCSV)
{
List<string> outputList = new List<string>();
char separator = isCSV ? ',' : '\t';
int startIndex = 0;
int endIndex = 0;
for (int i = 0; i < value.Length; i++)
{
char ch = value[i];
if (ch == separator)
{
outputList.Add(value.Substring(startIndex, endIndex - startIndex));
startIndex = endIndex + 1;
endIndex = startIndex;
}
else if (ch == '\"' && isCSV)
{
// skip until the ending quotes
i++;
if (i >= value.Length)
{
throw new FormatException(string.Format("value: {0} had a format exception", value));
}
char tempCh = value[i];
while (tempCh != '\"' && i < value.Length)
i++;
endIndex = i;
}
else if (i + 1 == value.Length)
{
// add the last value
outputList.Add(value.Substring(startIndex));
break;
}
else
{
endIndex++;
}
}
return outputList.ToArray();
}
}
}
CsvHelper.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using MoreLinq; // http://stackoverflow.com/questions/15265588/how-to-find-item-with-max-value-using-linq
namespace HQ.Util.General.CSV
{
public class CsvHelper
{
public static Dictionary<LineSeparator, Func<string, string[]>> DictionaryOfLineSeparatorAndItsFunc = new Dictionary<LineSeparator, Func<string, string[]>>();
static CsvHelper()
{
DictionaryOfLineSeparatorAndItsFunc[LineSeparator.Unknown] = ParseLineNotSeparated;
DictionaryOfLineSeparatorAndItsFunc[LineSeparator.Tab] = ParseLineTabSeparated;
DictionaryOfLineSeparatorAndItsFunc[LineSeparator.Semicolon] = ParseLineSemicolonSeparated;
DictionaryOfLineSeparatorAndItsFunc[LineSeparator.Comma] = ParseLineCommaSeparated;
}
// ******************************************************************
public enum LineSeparator
{
Unknown = 0,
Tab,
Semicolon,
Comma
}
// ******************************************************************
public static LineSeparator GuessCsvSeparator(string oneLine)
{
List<Tuple<LineSeparator, int>> listOfLineSeparatorAndThereFirstLineSeparatedValueCount = new List<Tuple<LineSeparator, int>>();
listOfLineSeparatorAndThereFirstLineSeparatedValueCount.Add(new Tuple<LineSeparator, int>(LineSeparator.Tab, CsvHelper.ParseLineTabSeparated(oneLine).Count()));
listOfLineSeparatorAndThereFirstLineSeparatedValueCount.Add(new Tuple<LineSeparator, int>(LineSeparator.Semicolon, CsvHelper.ParseLineSemicolonSeparated(oneLine).Count()));
listOfLineSeparatorAndThereFirstLineSeparatedValueCount.Add(new Tuple<LineSeparator, int>(LineSeparator.Comma, CsvHelper.ParseLineCommaSeparated(oneLine).Count()));
Tuple<LineSeparator, int> bestBet = listOfLineSeparatorAndThereFirstLineSeparatedValueCount.MaxBy((n)=>n.Item2);
if (bestBet != null && bestBet.Item2 > 1)
{
return bestBet.Item1;
}
return LineSeparator.Unknown;
}
// ******************************************************************
public static string[] ParseLineCommaSeparated(string line)
{
// CSV line parsing : From "jgr4" in http://www.kimgentes.com/worshiptech-web-tools-page/2008/10/14/regex-pattern-for-parsing-csv-files-with-embedded-commas-dou.html
var matches = Regex.Matches(line, @"\s?((?<x>(?=[,]+))|""(?<x>([^""]|"""")+)""|""(?<x>)""|(?<x>[^,]+)),?",
RegexOptions.ExplicitCapture);
string[] values = (from Match m in matches
select m.Groups["x"].Value.Trim().Replace("\"\"", "\"")).ToArray();
return values;
}
// ******************************************************************
public static string[] ParseLineTabSeparated(string line)
{
//var matchesTab = Regex.Matches(line, @"\s?((?<x>(?=[\t]+))|""(?<x>([^""]|"""")+)""|""(?<x>)""|(?<x>[^\t]+))\t?",
// RegexOptions.ExplicitCapture);
// Correction according to Cesar Morigaki from SO question: https://stackoverflow.com/questions/4118617/wpf-datagrid-pasting/5436437?noredirect=1#comment115043404_5436437
var matchesTab = Regex.Matches(line, @"[\r\n\f\v ]*?((?<x>(?=[\t]+))|""(?<x>([^""]|"""")+)""|""(?<x>)""|(?<x>[^\t]+))\t?",
RegexOptions.ExplicitCapture);
string[] values = (from Match m in matchesTab
select m.Groups["x"].Value.Trim().Replace("\"\"", "\"")).ToArray();
return values;
}
// ******************************************************************
public static string[] ParseLineSemicolonSeparated(string line)
{
// CSV line parsing : From "jgr4" in http://www.kimgentes.com/worshiptech-web-tools-page/2008/10/14/regex-pattern-for-parsing-csv-files-with-embedded-commas-dou.html
var matches = Regex.Matches(line, @"\s?((?<x>(?=[;]+))|""(?<x>([^""]|"""")+)""|""(?<x>)""|(?<x>[^;]+));?",
RegexOptions.ExplicitCapture);
string[] values = (from Match m in matches
select m.Groups["x"].Value.Trim().Replace("\"\"", "\"")).ToArray();
return values;
}
// ******************************************************************
public static string[] ParseLineNotSeparated(string line)
{
string [] lineValues = new string[1];
lineValues[0] = line;
return lineValues;
}
// ******************************************************************
public static List<string[]> ParseText(string text)
{
string[] lines = text.Split(new string[] { "\r\n" }, StringSplitOptions.None);
return ParseString(lines);
}
// ******************************************************************
public static List<string[]> ParseString(string[] lines)
{
List<string[]> result = new List<string[]>();
LineSeparator lineSeparator = LineSeparator.Unknown;
if (lines.Any())
{
lineSeparator = GuessCsvSeparator(lines[0]);
}
Func<string, string[]> funcParse = DictionaryOfLineSeparatorAndItsFunc[lineSeparator];
foreach (string line in lines)
{
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
result.Add(funcParse(line));
}
return result;
}
// ******************************************************************
}
}
ClipboardHelper2.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Windows;
using System.IO;
using System.Linq;
using System.Windows.Forms.VisualStyles;
using HQ.Util.General.CSV;
namespace HQ.Util.General.Clipboard
{
// Uses Clipboard in WPF (PresentationCore.dll in v4 of the framework)
public static class ClipboardHelper2
{
public delegate string[] ParseFormat(string value);
public static List<string[]> ParseClipboardData()
{
List<string[]> clipboardData = new List<string[]>();
// get the data and set the parsing method based on the format
// currently works with CSV and Text DataFormats
IDataObject dataObj = System.Windows.Clipboard.GetDataObject();
if (dataObj != null)
{
string[] formats = dataObj.GetFormats();
if (formats.Contains(DataFormats.CommaSeparatedValue))
{
string clipboardString = (string)dataObj.GetData(DataFormats.CommaSeparatedValue);
{
// EO: Subject to error when a CRLF is included as part of the data but it work for the moment and I will let it like it is
// WARNING ! Subject to errors
string[] lines = clipboardString.Split(new string[] { "\r\n" }, StringSplitOptions.None);
string[] lineValues;
foreach (string line in lines)
{
lineValues = CsvHelper.ParseLineCommaSeparated(line);
if (lineValues != null)
{
clipboardData.Add(lineValues);
}
}
}
}
else if (formats.Contains(DataFormats.Text))
{
string clipboardString = (string)dataObj.GetData(DataFormats.Text);
clipboardData = CsvHelper.ParseText(clipboardString);
}
}
return clipboardData;
}
}
}
关于WPF 数据网格粘贴,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4118617/
您能否建议如何在 Bootstrap 或 IE 兼容的 CSS 网格中,在没有 CSS 网格的情况下进行以下布局。 在大屏幕中 头部,左侧堆叠的 body 和右侧覆盖头部和 body 高度的图像。 [
我想在 Objective-C 中绘制一个 15*15 的网格。格子颜色是蓝色的,就像在诺基亚制作“贪吃蛇”游戏的棋盘一样。 我试过使用 for 循环来创建 subview ,但它似乎不起作用,我查看
我正在尝试将 CSS 网格与 grid-template-columns: repeat(auto-fill, auto) 一起使用,单元格被设置为最大宽度,导致每行一个元素。 p> 是否可以让元素宽
我正在努力在网格的自定义列上添加一个指向网站的简单、简单的链接。我用了 Inchoo blog为列添加自定义渲染器,它可以工作。我认为只需修改渲染并添加标签就足够了。但我的希望破灭了,行不通。 如何做
使用 Gnuplot 我绘制了下图 - 现在,正如您在图像中看到的那样,很难在线条之间识别出其末端的块。所以我想用不同的颜色或样式交替着色网格。 我现在用来给网格着色的代码是 - set style
假设我有一个非常简单的 WPF 网格(6 行 x 6 列),定义如下:
我有一个希望绑定(bind)到 WPF 网格的集合。 我面临的问题是列数是动态的并且取决于集合。这是一个简单的模型: public interface IRows { string Messa
我正在使用 Vaadin 8,我想制作某种混淆矩阵。我想知道是否可以根据单元格位置而不是数据提供者手动填充表格/网格的值。 referenceTable.addColumn(reference ->
我在 http://jsfiddle.net/TsRJy/ 上创建了一个带有 div 框的网格. 问题 我不知道如何使 a:hover 工作。 信息 重写 HTML 代码,因为表格不适合我。 http
银光处女在这里。如何使网格周围的用户控件自动调整大小以适应内部网格宽度?目前,当浏览器窗口更宽时,用户控件的显示尺寸约为 300 或 400 像素。它在数据网格周围呈现垂直和水平滚动条,这很丑陋。我想
这个问题已经有答案了: Equal width columns in CSS Grid (11 个回答) 已关闭 2 年前。 使用 CSS Grid,当您不知道会有多少个子项时,如何将所有子项保留在一
我想使用 CSS Grid 的 grid-template-areas。 但问题是我正在使用的 CMS 添加了大量额外的包装器。有没有办法忽略额外的包装?因为它弄乱了漂亮的网格区域...... 我正在
在我的Grid中,当我单击“操作”按钮(下面的代码中显示的“删除和编辑”按钮)时,我需要弹出一个窗口,而不用警告消息提醒用户; 在下面的代码中,我正在使用HANDLER handler: button
这个问题已经有答案了: Equal width columns in CSS Grid (11 个回答) 已关闭 2 年前。 使用 CSS Grid,当您不知道会有多少个子项时,如何将所有子项保留在一
我需要模拟一个仓库,其中有几辆自动驾驶车辆在给定的布局上移动,并具有简单的优先级规则。根据我的理解,这个问题可以通过离散事件模拟(DES)轻松解决,我会使用 SimPy为了这。 我看到的问题是,我似乎
在 ASP.NET 中,我可以让用户控件在页面上的表格中占据多个单元格: 用户控件1: foo bar 第1页: 并且自动调整列宽以适应最大的用户控件。 这也可以在 WPF
我正在寻找一种方法来实时搜索我的网格+要过滤的复选框。我有一个包含学生的网格(照片和姓名)。我想要的是有一个复选框,可以过滤学生所在的不同类(class)。还有一个搜索栏,我可以在其中输入学生姓名。
我正在使用 jQuery 和 jQuery UI 构建一个 Web 应用程序。我陷入了僵局。我需要的是一个 jQuery 网格,它具有可编辑字段,并以某种方式在这些可编辑单元格之一上合并一个自动完成字
我想知道是否有其他 JavaScript 组件可以提供具有多个分组的网格表示。下面是jqGrid的截图我扩展了允许该功能,但它需要获取所有数据。我希望在扩展分组时加载数据。 另一个修改后的 jqGri
我一直在为我将在此处描述的 CSS 问题而烦恼: 在下面的示例 ( https://codesandbox.io/s/jjq4km89y5 ) 中,您可以看到一个可滚动的内容(紫色背景)和一个被左侧面
我是一名优秀的程序员,十分优秀!