在自定义ListView控件上,我正在开发一个“导出到Excel”小按钮,它将ListView的所有内容发送到Excel。由于此按钮嵌入在ListView控件中,因此我不知道列出了哪种对象或显示了哪些列。
所以我的方法是通用的,只需解析所有列标题和所有行以将数据导出到Excel。但是在解析不可见的ListViewItem时,会得到null结果。一个解决方案是在我的ListView上设置VirtualizingStackPanel.VirtualizationMode =“False”,但是当你有数千行时,它会强烈影响GUI体验。
我正在寻找一种方法来加载所有ListViewItem,仅用于我的通用导出方法,并为GUI保持虚拟化。
有人可以帮我吗?
谢谢。
答案 0 :(得分:0)
我终于来了反思来解决我的问题。基本上,我首先解析所有列以查找绑定的属性名称。然后从ListView对Items集合进行一些反思,以找到属性值。
这是代码(尚未打磨):
private void OnExportToExcel(object sender, ExecutedRoutedEventArgs args)
{
if (this.Items.Count > 0)
{
// Ensure we have a visible and selected item
if (this.SelectedItem == null)
this.SelectedItem = this.Items[0];
this.ScrollIntoView(this.SelectedItem);
// Allow UI thread to update first or our selected lvi will be null if not visible
UIHelpers.AllowUIToUpdate();
List<string> columnPropertyBindingPathList = new List<string>();
int colIndex = 0;
// Get column binding path of underlying data
foreach (GridViewColumn h in ((GridView)this.View).Columns)
{
string bindingPath = "";
if (h.DisplayMemberBinding != null)
{
bindingPath = (h.DisplayMemberBinding as Binding).Path.Path;
}
else
{
ListViewItem lvi = this.ItemContainerGenerator.ContainerFromIndex(this.SelectedIndex) as ListViewItem;
if (lvi != null)
{
GridViewRowPresenter gvp = UIHelpers.FindVisualChild<GridViewRowPresenter>(lvi);
DependencyObject col = VisualTreeHelper.GetChild(gvp, colIndex);
TextBlock tb = col as TextBlock;
if (tb == null)
{
tb = UIHelpers.FindVisualChild<TextBlock>(col);
bindingPath = BindingOperations.GetBinding(tb, TextBlock.TextProperty).Path.Path;
}
}
}
colIndex++;
if (bindingPath != "")
columnPropertyBindingPathList.Add(bindingPath);
}
if (columnPropertyBindingPathList.Count > 0)
{
Mouse.SetCursor(Cursors.Wait);
// Init array to export to excel
object[,] dataArray = new object[this.Items.Count + 1, columnPropertyBindingPathList.Count];
// Add column header
for (int colCnt = 0; colCnt < columnPropertyBindingPathList.Count; colCnt++)
dataArray[0, colCnt] = columnPropertyBindingPathList[colCnt];
// Reflection to read underlying objects
int rowCnt = 1;
foreach (object obj in this.Items)
{
for (int colCnt = 0; colCnt < columnPropertyBindingPathList.Count; colCnt++)
dataArray[rowCnt, colCnt] = UIHelpers.GetPropValue(columnPropertyBindingPathList[colCnt], obj);
rowCnt++;
}
Mouse.SetCursor(Cursors.Arrow);
// Throw event
RoutedEventArgs newEventArgs = new RoutedEventArgs(EmListView.ExportToExcelEvent);
newEventArgs.Source = dataArray;
RaiseEvent(newEventArgs);
}
else
{
// Throw event
RoutedEventArgs newEventArgs = new RoutedEventArgs(EmListView.ExportToExcelEvent);
newEventArgs.Source = null;
RaiseEvent(newEventArgs);
}
}
else
{
// Throw event
RoutedEventArgs newEventArgs = new RoutedEventArgs(EmListView.ExportToExcelEvent);
newEventArgs.Source = null;
RaiseEvent(newEventArgs);
}
}
UIHelpers方法:
/// <summary>
/// Give the UI thread the time to refresh
/// </summary>
public static void AllowUIToUpdate()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Render, new DispatcherOperationCallback(delegate(object parameter)
{
frame.Continue = false;
return null;
}), null);
Dispatcher.PushFrame(frame);
}
/// <summary>
/// Find a visual child type inside a DependencyObject
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is T)
return (T)child;
else
{
T childOfChild = FindVisualChild<T>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
/// <summary>
/// Find a property value inside a object (even for multi level property)
/// </summary>
/// <param name="name"></param>
/// <param name="obj"></param>
/// <returns></returns>
public static Object GetPropValue(String name, Object obj)
{
foreach (String part in name.Split('.'))
{
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}