gpt4 book ai didi

WPF 数据网格粘贴

转载 作者:行者123 更新时间:2023-12-02 16:32:19 29 4
gpt4 key购买 nike

我在从 csv 粘贴到 wpf 数据网格时遇到问题 - 我已遵循此处的建议

Link

并且代码执行没有问题 - 但是,似乎所有新行都已创建,但只有第一行填充了数据。数据似乎不断被覆盖,以便剪贴板数据中的最后一项填充在第一行中,而所有其他行均为空白。我知道这一定是索引问题或其他问题,但我无法追踪它。

此外,当我查看网格可绑定(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 一起使用。非常重要

文森特的原始网站帖子:https://learn.microsoft.com/en-us/archive/blogs/vinsibal/pasting-content-to-new-rows-on-the-wpf-datagrid

注意:如果您无法添加行,请确保您的项目有一个默认构造函数。

更新于 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/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com