积极答复者
怎么样才能在Silverlight中显示 交叉表或者行列转置的DataGrid呢?

问题
答案
-
0)Bellow Is A Tested Example For You.
1) Xaml File
<UserControl
x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"><!-- Just For Customize The Data Grid, Optional -->
<UserControl.Resources>
<Style
x:Name="CssCrossHeader"
TargetType="sdk:DataGridColumnHeader">
<Setter
Property="Foreground"
Value="Red">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Center">
</Setter>
<Setter
Property="FontWeight"
Value="Bold">
</Setter>
</Style>
<Style
x:Name="CssColumnHeader"
TargetType="sdk:DataGridColumnHeader">
<Setter
Property="Foreground"
Value="Red">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Center">
</Setter>
<Setter
Property="FontWeight"
Value="Bold">
</Setter>
</Style>
<Style
x:Name="CssTitleCell"
TargetType="sdk:DataGridCell">
<Setter
Property="Foreground"
Value="Red">
</Setter>
<Setter
Property="FontWeight"
Value="Bold"></Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Left">
</Setter>
</Style>
<Style
x:Name="CssValueCell"
TargetType="sdk:DataGridCell">
<Setter
Property="Foreground"
Value="Blue">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Right">
</Setter>
</Style>
</UserControl.Resources><!-- Test Data Grid, Required When Testing -->
<Grid
x:Name="GrdRoot">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Vertical">
<sdk:DataGrid
x:Name="DgrTest"
Width="600"
Height="300" />
<Button
x:Name="CmdShow1"
Content="Show Test Data 1 (Name As Column Header, Course As Row Header)"></Button>
<Button
x:Name="CmdShow2"
Content="Show Test Data 2 (Course As Column Header, Name As Row Header)"></Button>
</StackPanel>
</Grid>
</UserControl>2)Cs File
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Collections;namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.CmdShow1.Click += new RoutedEventHandler(CmdShow1_Click);
this.CmdShow2.Click += new RoutedEventHandler(CmdShow2_Click);
}private void CmdShow1_Click(object sender, RoutedEventArgs e)
{
//Name As Column Header, Course As Row Header
var X = new T4DataCrossViewHelper()
{
//Required Calling Parameters
DataSource = CTestData.TestData, DisplayDataGrid = this.DgrTest,
XTitlePropertyName = "Name", YTitlePropertyName = "Course", ValueProppertyName = "Score",
//Optional Calling Parameters
XSortType = T4DataCrossViewHelper.ESortType.Asc,
YSortType = T4DataCrossViewHelper.ESortType.Asc,
ValueFindMode = T4DataCrossViewHelper.EFindMode.Average,
CrossHeader = @"Course \ Name", ValueFormat = "#0.00",
CrossHeaderStyle = this.CssCrossHeader, ColumnHeaderStyle = this.CssColumnHeader,
TitleCellStyle = this.CssTitleCell, ValueCellStyle = this.CssValueCell,
};
X.InitDataGrid();
}private void CmdShow2_Click(object sender, RoutedEventArgs e)
{
//Course As Column Header, Name As Row Header
var X = new T4DataCrossViewHelper()
{
//Required Calling Parameters
DataSource = CTestData.TestData, DisplayDataGrid = this.DgrTest,
XTitlePropertyName = "Course", YTitlePropertyName = "Name", ValueProppertyName = "Score",
};
X.InitDataGrid();
}
}//Test Data Source (I Guess Your Data From WCF Organized In This Way)
public static class CTestData
{
public static List<CDataItem> TestData { get; set; }
static CTestData()
{
TestData = new List<CDataItem>();
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "Chinese", Score = 10.0 });
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "English", Score = 20.0 });
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "Math", Score = 30.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "Chinese", Score = 40.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "English", Score = 50.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "Math", Score = 60.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "Chinese", Score = 70.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "English", Score = 80.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "Math", Score = 90.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Chinese", Score = 100.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "English", Score = 110.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Math", Score = 120.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Math", Score = 125.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "Chinese", Score = 130.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "English", Score = 140.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "Math", Score = 150.0 });
TestData.Add(new CDataItem() { Name = "I", Course = "Chinese", Score = 160.0 });
TestData.Add(new CDataItem() { Name = "I", Course = "Chinese", Score = 165.0 });
TestData.Add(new CDataItem() { Name = "You", Course = "English", Score = 170.0 });
TestData.Add(new CDataItem() { Name = "You", Course = "English", Score = 175.0 });
}
}
public class CDataItem
{
public string Name { get; set; }
public string Course { get; set; }
public double Score { get; set; }
}/// <summary>
/// Transpose Data View Helper Class
/// TFSoft - Still in Writting, But Maybe Cancelled Deppending On My Interest Or Your Needs.
/// </summary>
public class T4DataTransposeViewHelper
{
}/// <summary>
/// Cross Data View Helper Class
/// TFSoft - 2011/06/09
/// TFSoft = Simple, Nice, Elegant
/// Copyright Free, But Strongly Recommend Dont Remove TFSoft Remark.
///
/// Addtional Notes:
/// TFSoft Is An Agricultural Researcher (Really A Farmer), But Love Computer Programming.
/// TFSoft Has Programing Expirence Of Over 30 Years, And Play With Coding 4-8 Hours A Day In Average.
/// </summary>
public class T4DataCrossViewHelper
{
/// <summary>
/// Cross Data Source, Required
/// </summary>
public IEnumerable DataSource { get; set; }/// <summary>
/// Display Data Grid, Required
/// </summary>
public DataGrid DisplayDataGrid { get; set; }/// <summary>
/// Horizontal Title Property Name, Required
/// </summary>
public string XTitlePropertyName { get; set; }/// <summary>
/// XValue Sort Type, Optional
/// </summary>
public ESortType XSortType { get; set; }/// <summary>
/// Vertical Title Property Name, Required
/// </summary>
public string YTitlePropertyName { get; set; }/// <summary>
/// YValue Sort Type, Optional
/// </summary>
public ESortType YSortType { get; set; }/// <summary>
/// Value Property Name, Required
/// </summary>
public string ValueProppertyName { get; set; }/// <summary>
/// Value Display Format, Optional
/// </summary>
public string ValueFormat { get; set; }/// <summary>
/// Value Find Mode, Optional
/// </summary>
public EFindMode ValueFindMode { get; set; }/// <summary>
/// Value Cell Style, Optional
/// </summary>
public Style ValueCellStyle { get; set; }/// <summary>
/// Cross Header Content, Optional
/// </summary>
public object CrossHeader { get; set; }/// <summary>
/// Cross Header Style, Optional
/// </summary>
public Style CrossHeaderStyle { get; set; }/// <summary>
/// Column Header (Data Grid Column Header) Style, Optional
/// </summary>
public Style ColumnHeaderStyle { get; set; }/// <summary>
/// Title Cell (Cell In Left Most Column) Style, Optional
/// </summary>
public Style TitleCellStyle { get; set; }/// <summary>
/// Init Your Data Grid, Called By Your Code
/// </summary>
public void InitDataGrid()
{
DisplayDataGrid.ItemsSource = null;
DisplayDataGrid.AutoGenerateColumns = false;
DisplayDataGrid.Columns.Clear();var LnqXData = null as IEnumerable<object>;
switch (XSortType)
{
case ESortType.None:
LnqXData = (from X in DataSource.Cast<object>()
let X1 = InvokePropertyValue(X, XTitlePropertyName)
select X1).Distinct();
break;
case ESortType.Asc:
LnqXData = (from X in DataSource.Cast<object>()
let X1 = InvokePropertyValue(X, XTitlePropertyName)
orderby X1 ascending
select X1).Distinct();
break;
case ESortType.Desc:
LnqXData = (from X in DataSource.Cast<object>()
let X1 = InvokePropertyValue(X, XTitlePropertyName)
orderby X1 descending
select X1).Distinct();
break;
}var LnqYData = null as IEnumerable<object>;
switch (YSortType)
{
case ESortType.None:
LnqYData = (from X in DataSource.Cast<Object>()
let X1 = InvokePropertyValue(X, YTitlePropertyName)
select X1).Distinct();
break;
case ESortType.Asc:
LnqYData = (from X in DataSource.Cast<Object>()
let X1 = InvokePropertyValue(X, YTitlePropertyName)
orderby X1 ascending
select X1).Distinct();
break;
case ESortType.Desc:
LnqYData = (from X in DataSource.Cast<Object>()
let X1 = InvokePropertyValue(X, YTitlePropertyName)
orderby X1 descending
select X1).Distinct();
break;
}//Title Column
DisplayDataGrid.Columns.Add(new DataGridTextColumn()
{
Header = CrossHeader, HeaderStyle = CrossHeaderStyle,
Binding = new Binding() { Path = new PropertyPath(""), },
CellStyle = TitleCellStyle, IsReadOnly = true,
});//Value Column
foreach (var XValue in LnqXData)
{
DisplayDataGrid.Columns.Add(new DataGridTextColumn()
{
Header = XValue, HeaderStyle = ColumnHeaderStyle,
Binding = new Binding()
{
Path = new PropertyPath(""),
Converter = new CCrossDataConverter()
{
DataSource = DataSource,
ValueFindMode = ValueFindMode,
XTitlePropertyName = XTitlePropertyName,
YTitlePropertyName = YTitlePropertyName,
ValueProppertyName = ValueProppertyName,
},
ConverterParameter = XValue,
StringFormat = ValueFormat,
},
CellStyle = ValueCellStyle, IsReadOnly = true,
});
}
DisplayDataGrid.ItemsSource = LnqYData;
}
private static object InvokePropertyValue(object Instance, string PropertyName)
{
var Lnq = from X in Instance.GetType().GetProperties()
where string.Compare(X.Name, PropertyName, StringComparison.OrdinalIgnoreCase) == 0
select X.GetValue(Instance, null);
var Rlt = Lnq.FirstOrDefault(); return Rlt;
}
/// <summary>
/// Cross Data Value Converter, Called Only By T4CrossDataHelper
/// </summary>
public class CCrossDataConverter : IValueConverter
{
public IEnumerable DataSource { get; set; }
public string XTitlePropertyName { get; set; }
public string YTitlePropertyName { get; set; }
public string ValueProppertyName { get; set; }
public EFindMode ValueFindMode { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var Lnq = from X in DataSource.Cast<object>()
where InvokePropertyValue(X, XTitlePropertyName).Equals(parameter) &&
InvokePropertyValue(X, YTitlePropertyName).Equals(value)
select InvokePropertyValue(X, ValueProppertyName);
var Rlt = Lnq.FirstOrDefault();
switch (ValueFindMode)
{
case EFindMode.First: break;
case EFindMode.Last: if (Rlt != null) { Rlt = Lnq.LastOrDefault(); }; break;
case EFindMode.Min: if (Rlt != null) { Rlt = Lnq.Min(); }; break;
case EFindMode.Max: if (Rlt != null) { Rlt = Lnq.Max(); }; break;
case EFindMode.Sum: if (Rlt != null) { Rlt = Lnq.Sum(lX => System.Convert.ToDouble(lX)); }; break;
case EFindMode.Average: if (Rlt != null) { Rlt = Lnq.Average(lX => System.Convert.ToDouble(lX)); }; break;
}
return Rlt;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
/// <summary>
/// Value Find Mode Enums
/// </summary>
public enum EFindMode
{
First = 0, Last = 1, Min = 2, Max = 3, Sum = 4, Average = 5
}
/// <summary>
/// Data Sort Type Enums
/// </summary>
public enum ESortType
{
None = 0, Asc = 1, Desc = 2
}
}
}- 已标记为答案 天使坠Moderator 2011年6月11日 10:01
-
前几天无法登录论坛,未能及时回答,现回答如下:
应该指出的是,数据值 可以取平均,最大,最小,第一个,最后一个。
1)xaml
<UserControl
x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"><UserControl.Resources>
<Style
x:Name="CssYTitleHeader"
TargetType="sdk:DataGridColumnHeader">
<Setter
Property="Foreground"
Value="Green">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Center">
</Setter>
<Setter
Property="FontWeight"
Value="Bold">
</Setter>
</Style>
<Style
x:Name="CssXTitleHeader"
TargetType="sdk:DataGridColumnHeader">
<Setter
Property="Foreground"
Value="Red">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Center">
</Setter>
<Setter
Property="FontWeight"
Value="Bold">
</Setter>
</Style>
<Style
x:Name="CssYTitleCell"
TargetType="sdk:DataGridCell">
<Setter
Property="Foreground"
Value="Green">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Left">
</Setter>
</Style>
<Style
x:Name="CssValueCell"
TargetType="sdk:DataGridCell">
<Setter
Property="Foreground"
Value="Blue">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Right">
</Setter>
</Style>
</UserControl.Resources><!-- Test Data Grid, Required When Testing -->
<Grid
x:Name="GrdRoot">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Vertical">
<sdk:DataGrid
x:Name="DgrTest"
Width="600"
Height="300" />
<Button
x:Name="CmdShow"
Content="Show Corss Data"></Button>
</StackPanel>
</Grid>
</UserControl>2)cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.CmdShow.Click += CmdShow_Click;
}private void CmdShow_Click(object sender, RoutedEventArgs e)
{
var X = new T4CrossViewHelperEx()
{
//Required Parameters
DataSource = CTestData.TestData,
DisplayDataGrid = this.DgrTest,
YTitlePropertyNames = "Name,Age",
XTitlePropertyName = "Course",
ValuePropertyName = "Score",
//Optional Parameters
YTitlePropertyCaptions = "NameEx,AgeEx",
ValueFormat = "#0.0",
ValueFindMode = T4CrossViewHelperEx.EValueFindMode.Average,
ValueCellStyle = this.CssValueCell,
YTitleCellStyle = this.CssYTitleCell,
YHeaderStyle = this.CssYTitleHeader,
XHeaderStyle = this.CssXTitleHeader,
};
X.InitDataGrid();
}
public static class CTestData
{
public static List<CDataItem> TestData { get; set; }
static CTestData()
{
TestData = new List<CDataItem>();
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "Chinese", Score = 10.0 });
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "English", Score = 20.0 });
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "Math", Score = 30.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "Chinese", Score = 40.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "English", Score = 50.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "Math", Score = 60.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "Chinese", Score = 70.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "English", Score = 80.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "Math", Score = 90.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Chinese", Score = 100.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "English", Score = 110.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Math", Score = 120.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Math", Score = 125.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "Chinese", Score = 130.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "English", Score = 140.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "Math", Score = 150.0 });
TestData.Add(new CDataItem() { Name = "I", Age = "50Y", Course = "Chinese", Score = 160.0 });
TestData.Add(new CDataItem() { Name = "I", Age = "50Y", Course = "Chinese", Score = 165.0 });
TestData.Add(new CDataItem() { Name = "You", Age = "60Y", Course = "English", Score = 170.0 });
TestData.Add(new CDataItem() { Name = "You", Age = "60Y", Course = "English", Score = 175.0 });
}
}
public class CDataItem
{
public string Name { get; set; }
public string Course { get; set; }
public double Score { get; set; }
public string Age { get; set; }
}/// <summary>
/// T4CrossViewHelperEx
/// </summary>
public class T4CrossViewHelperEx
{
/// <summary>
/// DataSource, Required
/// </summary>
public IEnumerable DataSource { get; set; }/// <summary>
/// DisplayDataGrid, Required
/// </summary>
public DataGrid DisplayDataGrid { get; set; }/// <summary>
/// XTitlePropertyName, Required
/// </summary>
public string XTitlePropertyName { get; set; }/// <summary>
/// YTitlePropertyNames, Required
/// </summary>
public string YTitlePropertyNames { get; set; }/// <summary>
/// ValuePropertyName, Required
/// </summary>
public string ValuePropertyName { get; set; }/// <summary>
/// YTitlePropertyCaptions, Optional
/// </summary>
public string YTitlePropertyCaptions { get; set; }/// <summary>
/// XHeaderStyle, Optional
/// </summary>
public Style XHeaderStyle { get; set; }/// <summary>
/// YHeaderStyle, Optional
/// </summary>
public Style YHeaderStyle { get; set; }/// <summary>
/// YTitleCellStyle, Optional
/// </summary>
public Style YTitleCellStyle { get; set; }/// <summary>
/// ValueCellStyle, Optional
/// </summary>
public Style ValueCellStyle { get; set; }/// <summary>
/// ValueFormat, Optional
/// </summary>
public string ValueFormat { get; set; }/// <summary>
/// ValueFindMode, Optional
/// </summary>
public EValueFindMode ValueFindMode { get; set; }/// <summary>
/// InitDataGrid
/// </summary>
public void InitDataGrid()
{DisplayDataGrid.ItemsSource = null;
DisplayDataGrid.AutoGenerateColumns = false;
DisplayDataGrid.Columns.Clear();var LnqYData = (from X in DataSource.Cast<object>()
let X1 = GetDataItemValues(X, YTitlePropertyNames)
select X1).Distinct(new CDictEQ());
//YTitle Columns
if (1 == 1)
{
var A1 = YTitlePropertyNames.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
var A2 = new string[] { };
if (!string.IsNullOrWhiteSpace(YTitlePropertyCaptions))
{
A2 = YTitlePropertyCaptions.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
}
var Lnq = from X in Enumerable.Range(0, A1.Length)
let XPath = "[" + A1[X] + "]"
let XHeader = X < A2.Length ? A2[X] : A1[X]
select new { Path = XPath, Header = XHeader };
foreach (var Itm in Lnq)
{
DisplayDataGrid.Columns.Add(new DataGridTextColumn()
{
IsReadOnly = true,
Header = Itm.Header,
HeaderStyle = YHeaderStyle,
Binding = new Binding(Itm.Path),
CellStyle = YTitleCellStyle,
});
};
}
//Value Column
if (1 == 1)
{
var LnqXData = (from X in DataSource.Cast<object>()
let X1 = GetDataItemValue(X, XTitlePropertyName)
orderby X1
select X1).Distinct();
foreach (var Itm in LnqXData)
{
DisplayDataGrid.Columns.Add(new DataGridTextColumn()
{
IsReadOnly = true,
Header = Itm,
HeaderStyle = XHeaderStyle,
Binding = new Binding()
{
Path = new PropertyPath(""),
StringFormat = ValueFormat,
Converter = new CValueConverter()
{
DataSource = DataSource,
XTitlePropertyName = XTitlePropertyName,
ValuePropertyName = ValuePropertyName,
ValueFindMode = ValueFindMode,
},
ConverterParameter = Itm,
},
CellStyle = ValueCellStyle,
});
}
}
DisplayDataGrid.ItemsSource = LnqYData;
}/// <summary>
/// CDictEQ, Called Only By T4CrossViewHelper
/// </summary>
public class CDictEQ : IEqualityComparer<Dictionary<string, object>>
{
public bool Equals(Dictionary<string, object> DicA, Dictionary<string, object> DicB)
{
var Rlt = false;
if (DicA == null || DicB == null)
{
Rlt =
((DicA == null && DicB != null) || (DicA != null && DicB == null)) ?
false : true;
}
else
{
var Lnq = from X in DicA.Keys
where !ObjEq(DicA[X], DicB[X])
select X;
Rlt = Lnq.Count() > 0 ? false : true;
}
return Rlt;
}private bool ObjEq(object O1, object O2)
{
var Rlt = false;
if (O1 == null || O2 == null)
{
Rlt =
((O1 == null && O2 != null) || (O1 != null && O2 == null)) ?
false : true;
}
else
{
Rlt = O1.Equals(O2) ? true : false;
}
return Rlt;
}public int GetHashCode(Dictionary<string, object> Dic)
{
var Rlt = 0;
var Lnq = from X in Dic.Keys
let X1 = Dic[X]
let X2 = X1 == null ? 0 : X1.GetHashCode()
select X2;
foreach (var Itm in Lnq) { Rlt = Rlt ^ Itm; }; return Rlt;
}
}/// <summary>
/// CValueConverter, Called Only By T4CrossViewHelper
/// </summary>
public class CValueConverter : IValueConverter
{
public IEnumerable DataSource { get; set; }
public string XTitlePropertyName { get; set; }
public string ValuePropertyName { get; set; }
public EValueFindMode ValueFindMode { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var YValue = value as Dictionary<string, object>;
var XValue = parameter;
var Lnq = from X in DataSource.Cast<object>()
let X1 = GetDataItemValues(X, string.Join(",", YValue.Keys))
where (new CDictEQ()).Equals(YValue, X1)
let X2 = GetDataItemValue(X, XTitlePropertyName)
where (X2 == null && XValue == null) || (X2 != null && X2.Equals(XValue))
let X3 = GetDataItemValue(X, ValuePropertyName)
select X3;
var Rlt = Lnq.FirstOrDefault();
switch (ValueFindMode)
{
case EValueFindMode.First: break;
case EValueFindMode.Last: Rlt = Lnq.Last(); break;
case EValueFindMode.Average: if (Rlt != null) { Rlt = Lnq.Average(lX => (double)lX); }; break;
case EValueFindMode.Min: Rlt = Lnq.Min(); break;
case EValueFindMode.Max: Rlt = Lnq.Max(); break;
}
return Rlt;
}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}/// <summary>
/// EValueFindMode
/// </summary>
public enum EValueFindMode
{
First = 0, Last = 1, Average = 2, Min = 3, Max = 4
}/// <summary>
/// GetDataItemValues
/// </summary>
/// <param name="DataItem"></param>
/// <param name="PropNames"></param>
/// <returns></returns>
private static Dictionary<string, object> GetDataItemValues(object DataItem, string PropNames)
{
var Lnq = from X in PropNames.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)
let XKey = X
let XValue = GetDataItemValue(DataItem, X)
select new { Key = XKey, Value = XValue };
var Rlt = Lnq.ToDictionary(lX => lX.Key, lX => lX.Value); return Rlt;
}/// <summary>
/// GetDataItemValue
/// </summary>
/// <param name="DataItem"></param>
/// <param name="PropName"></param>
/// <returns></returns>
private static object GetDataItemValue(object DataItem, string PropName)
{
var Lnq = from X in DataItem.GetType().GetProperties()
where X.Name.Trim().ToUpper() == PropName.Trim().ToUpper()
select X.GetValue(DataItem, null);
var Rlt = Lnq.FirstOrDefault(); return Rlt;
}
}
}
}
- 已标记为答案 Anton Jin 2011年6月17日 5:37
全部回复
-
0)只要你的SQL语句过了关,你尝试在SQL中生成交叉表也是可以的。生成后,可以直接绑定到SL的DataGrid,不过你用的是数据实体,数据实体是自动生成的,不好动态生成,因此,即使你生成了符合格式的数据,采用数据实体那套方案,要传给SL也是有一定困难的,
1)如果你用TFSoft研制的T4Data系列,仅用5行以内代码就可实现。
2)不过即使你不用TFSoft的T4Data,也可以把由WCF传来的数据实体,用反射的方法转置一下,生成一个新的实体,再绑定到SL的DataGrid。
21)为什么非要用反射,是因为这些字段(数据项)未必是死的,可能需要动态转置,省得不一样的字段,重复一些没有必要的代码。
22)反射法不是最容易的方法,而且不是一般人能搞清楚的方法。尤其是SL的反射与。net全框架的反射,相差太多,实现起来比较麻烦,T4Data早期版本,采用那反射。
3)还一种思路,那就是动态生成DataGrid,也能实现。
----------------
其实只要你愿意写代码,这个不会太难做到。
这是一个业余老程序员对你的提示。
如果我没事情,并且有兴趣,我会帮你写一个通用的交叉列表辅助类给你,暂时就叫 T4CrossDataViewHelper 吧,你等着。
-
0)Bellow Is A Tested Example For You.
1) Xaml File
<UserControl
x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"><!-- Just For Customize The Data Grid, Optional -->
<UserControl.Resources>
<Style
x:Name="CssCrossHeader"
TargetType="sdk:DataGridColumnHeader">
<Setter
Property="Foreground"
Value="Red">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Center">
</Setter>
<Setter
Property="FontWeight"
Value="Bold">
</Setter>
</Style>
<Style
x:Name="CssColumnHeader"
TargetType="sdk:DataGridColumnHeader">
<Setter
Property="Foreground"
Value="Red">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Center">
</Setter>
<Setter
Property="FontWeight"
Value="Bold">
</Setter>
</Style>
<Style
x:Name="CssTitleCell"
TargetType="sdk:DataGridCell">
<Setter
Property="Foreground"
Value="Red">
</Setter>
<Setter
Property="FontWeight"
Value="Bold"></Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Left">
</Setter>
</Style>
<Style
x:Name="CssValueCell"
TargetType="sdk:DataGridCell">
<Setter
Property="Foreground"
Value="Blue">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Right">
</Setter>
</Style>
</UserControl.Resources><!-- Test Data Grid, Required When Testing -->
<Grid
x:Name="GrdRoot">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Vertical">
<sdk:DataGrid
x:Name="DgrTest"
Width="600"
Height="300" />
<Button
x:Name="CmdShow1"
Content="Show Test Data 1 (Name As Column Header, Course As Row Header)"></Button>
<Button
x:Name="CmdShow2"
Content="Show Test Data 2 (Course As Column Header, Name As Row Header)"></Button>
</StackPanel>
</Grid>
</UserControl>2)Cs File
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Collections;namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.CmdShow1.Click += new RoutedEventHandler(CmdShow1_Click);
this.CmdShow2.Click += new RoutedEventHandler(CmdShow2_Click);
}private void CmdShow1_Click(object sender, RoutedEventArgs e)
{
//Name As Column Header, Course As Row Header
var X = new T4DataCrossViewHelper()
{
//Required Calling Parameters
DataSource = CTestData.TestData, DisplayDataGrid = this.DgrTest,
XTitlePropertyName = "Name", YTitlePropertyName = "Course", ValueProppertyName = "Score",
//Optional Calling Parameters
XSortType = T4DataCrossViewHelper.ESortType.Asc,
YSortType = T4DataCrossViewHelper.ESortType.Asc,
ValueFindMode = T4DataCrossViewHelper.EFindMode.Average,
CrossHeader = @"Course \ Name", ValueFormat = "#0.00",
CrossHeaderStyle = this.CssCrossHeader, ColumnHeaderStyle = this.CssColumnHeader,
TitleCellStyle = this.CssTitleCell, ValueCellStyle = this.CssValueCell,
};
X.InitDataGrid();
}private void CmdShow2_Click(object sender, RoutedEventArgs e)
{
//Course As Column Header, Name As Row Header
var X = new T4DataCrossViewHelper()
{
//Required Calling Parameters
DataSource = CTestData.TestData, DisplayDataGrid = this.DgrTest,
XTitlePropertyName = "Course", YTitlePropertyName = "Name", ValueProppertyName = "Score",
};
X.InitDataGrid();
}
}//Test Data Source (I Guess Your Data From WCF Organized In This Way)
public static class CTestData
{
public static List<CDataItem> TestData { get; set; }
static CTestData()
{
TestData = new List<CDataItem>();
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "Chinese", Score = 10.0 });
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "English", Score = 20.0 });
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "Math", Score = 30.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "Chinese", Score = 40.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "English", Score = 50.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "Math", Score = 60.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "Chinese", Score = 70.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "English", Score = 80.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "Math", Score = 90.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Chinese", Score = 100.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "English", Score = 110.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Math", Score = 120.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Math", Score = 125.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "Chinese", Score = 130.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "English", Score = 140.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "Math", Score = 150.0 });
TestData.Add(new CDataItem() { Name = "I", Course = "Chinese", Score = 160.0 });
TestData.Add(new CDataItem() { Name = "I", Course = "Chinese", Score = 165.0 });
TestData.Add(new CDataItem() { Name = "You", Course = "English", Score = 170.0 });
TestData.Add(new CDataItem() { Name = "You", Course = "English", Score = 175.0 });
}
}
public class CDataItem
{
public string Name { get; set; }
public string Course { get; set; }
public double Score { get; set; }
}/// <summary>
/// Transpose Data View Helper Class
/// TFSoft - Still in Writting, But Maybe Cancelled Deppending On My Interest Or Your Needs.
/// </summary>
public class T4DataTransposeViewHelper
{
}/// <summary>
/// Cross Data View Helper Class
/// TFSoft - 2011/06/09
/// TFSoft = Simple, Nice, Elegant
/// Copyright Free, But Strongly Recommend Dont Remove TFSoft Remark.
///
/// Addtional Notes:
/// TFSoft Is An Agricultural Researcher (Really A Farmer), But Love Computer Programming.
/// TFSoft Has Programing Expirence Of Over 30 Years, And Play With Coding 4-8 Hours A Day In Average.
/// </summary>
public class T4DataCrossViewHelper
{
/// <summary>
/// Cross Data Source, Required
/// </summary>
public IEnumerable DataSource { get; set; }/// <summary>
/// Display Data Grid, Required
/// </summary>
public DataGrid DisplayDataGrid { get; set; }/// <summary>
/// Horizontal Title Property Name, Required
/// </summary>
public string XTitlePropertyName { get; set; }/// <summary>
/// XValue Sort Type, Optional
/// </summary>
public ESortType XSortType { get; set; }/// <summary>
/// Vertical Title Property Name, Required
/// </summary>
public string YTitlePropertyName { get; set; }/// <summary>
/// YValue Sort Type, Optional
/// </summary>
public ESortType YSortType { get; set; }/// <summary>
/// Value Property Name, Required
/// </summary>
public string ValueProppertyName { get; set; }/// <summary>
/// Value Display Format, Optional
/// </summary>
public string ValueFormat { get; set; }/// <summary>
/// Value Find Mode, Optional
/// </summary>
public EFindMode ValueFindMode { get; set; }/// <summary>
/// Value Cell Style, Optional
/// </summary>
public Style ValueCellStyle { get; set; }/// <summary>
/// Cross Header Content, Optional
/// </summary>
public object CrossHeader { get; set; }/// <summary>
/// Cross Header Style, Optional
/// </summary>
public Style CrossHeaderStyle { get; set; }/// <summary>
/// Column Header (Data Grid Column Header) Style, Optional
/// </summary>
public Style ColumnHeaderStyle { get; set; }/// <summary>
/// Title Cell (Cell In Left Most Column) Style, Optional
/// </summary>
public Style TitleCellStyle { get; set; }/// <summary>
/// Init Your Data Grid, Called By Your Code
/// </summary>
public void InitDataGrid()
{
DisplayDataGrid.ItemsSource = null;
DisplayDataGrid.AutoGenerateColumns = false;
DisplayDataGrid.Columns.Clear();var LnqXData = null as IEnumerable<object>;
switch (XSortType)
{
case ESortType.None:
LnqXData = (from X in DataSource.Cast<object>()
let X1 = InvokePropertyValue(X, XTitlePropertyName)
select X1).Distinct();
break;
case ESortType.Asc:
LnqXData = (from X in DataSource.Cast<object>()
let X1 = InvokePropertyValue(X, XTitlePropertyName)
orderby X1 ascending
select X1).Distinct();
break;
case ESortType.Desc:
LnqXData = (from X in DataSource.Cast<object>()
let X1 = InvokePropertyValue(X, XTitlePropertyName)
orderby X1 descending
select X1).Distinct();
break;
}var LnqYData = null as IEnumerable<object>;
switch (YSortType)
{
case ESortType.None:
LnqYData = (from X in DataSource.Cast<Object>()
let X1 = InvokePropertyValue(X, YTitlePropertyName)
select X1).Distinct();
break;
case ESortType.Asc:
LnqYData = (from X in DataSource.Cast<Object>()
let X1 = InvokePropertyValue(X, YTitlePropertyName)
orderby X1 ascending
select X1).Distinct();
break;
case ESortType.Desc:
LnqYData = (from X in DataSource.Cast<Object>()
let X1 = InvokePropertyValue(X, YTitlePropertyName)
orderby X1 descending
select X1).Distinct();
break;
}//Title Column
DisplayDataGrid.Columns.Add(new DataGridTextColumn()
{
Header = CrossHeader, HeaderStyle = CrossHeaderStyle,
Binding = new Binding() { Path = new PropertyPath(""), },
CellStyle = TitleCellStyle, IsReadOnly = true,
});//Value Column
foreach (var XValue in LnqXData)
{
DisplayDataGrid.Columns.Add(new DataGridTextColumn()
{
Header = XValue, HeaderStyle = ColumnHeaderStyle,
Binding = new Binding()
{
Path = new PropertyPath(""),
Converter = new CCrossDataConverter()
{
DataSource = DataSource,
ValueFindMode = ValueFindMode,
XTitlePropertyName = XTitlePropertyName,
YTitlePropertyName = YTitlePropertyName,
ValueProppertyName = ValueProppertyName,
},
ConverterParameter = XValue,
StringFormat = ValueFormat,
},
CellStyle = ValueCellStyle, IsReadOnly = true,
});
}
DisplayDataGrid.ItemsSource = LnqYData;
}
private static object InvokePropertyValue(object Instance, string PropertyName)
{
var Lnq = from X in Instance.GetType().GetProperties()
where string.Compare(X.Name, PropertyName, StringComparison.OrdinalIgnoreCase) == 0
select X.GetValue(Instance, null);
var Rlt = Lnq.FirstOrDefault(); return Rlt;
}
/// <summary>
/// Cross Data Value Converter, Called Only By T4CrossDataHelper
/// </summary>
public class CCrossDataConverter : IValueConverter
{
public IEnumerable DataSource { get; set; }
public string XTitlePropertyName { get; set; }
public string YTitlePropertyName { get; set; }
public string ValueProppertyName { get; set; }
public EFindMode ValueFindMode { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var Lnq = from X in DataSource.Cast<object>()
where InvokePropertyValue(X, XTitlePropertyName).Equals(parameter) &&
InvokePropertyValue(X, YTitlePropertyName).Equals(value)
select InvokePropertyValue(X, ValueProppertyName);
var Rlt = Lnq.FirstOrDefault();
switch (ValueFindMode)
{
case EFindMode.First: break;
case EFindMode.Last: if (Rlt != null) { Rlt = Lnq.LastOrDefault(); }; break;
case EFindMode.Min: if (Rlt != null) { Rlt = Lnq.Min(); }; break;
case EFindMode.Max: if (Rlt != null) { Rlt = Lnq.Max(); }; break;
case EFindMode.Sum: if (Rlt != null) { Rlt = Lnq.Sum(lX => System.Convert.ToDouble(lX)); }; break;
case EFindMode.Average: if (Rlt != null) { Rlt = Lnq.Average(lX => System.Convert.ToDouble(lX)); }; break;
}
return Rlt;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
/// <summary>
/// Value Find Mode Enums
/// </summary>
public enum EFindMode
{
First = 0, Last = 1, Min = 2, Max = 3, Sum = 4, Average = 5
}
/// <summary>
/// Data Sort Type Enums
/// </summary>
public enum ESortType
{
None = 0, Asc = 1, Desc = 2
}
}
}- 已标记为答案 天使坠Moderator 2011年6月11日 10:01
-
如果需要帮助,请尽量列举数据源的格式,并且附上模拟的数据
这样,我搞起来就省去了很多时间,也更能满足你的要求。
这里的提问者总是不给出模拟数据,让有心帮你解决的人,添加了不少繁琐的事情,还有我不喜欢C#,原因是很多C#程序员采用违背自然语言习惯的但又是非常流行的“驼峰命名法”进行变量命名,看起来特别别扭,因此,给出的代码和你们的有点不一样,可能让你看起来不很舒服。(我是用VB.net的,C#只是最近刚接触的语言)。
TFSoft一贯追求简单/美好/高雅
TFSoft = Simple, Nice, Elegant.
-------------------------------------------------增加一些字段,我觉得应该不会太复杂,
友情提示:
1)YTitlePropertyName ==> YTitlePropertyNames ...
2) 在你理解了我良苦用心的基础上,很快就能自己修改一下相应代码。
-
模拟数据
修改实体
、
//Test Data Source (I Guess Your Data From WCF Organized In This Way) public static class CTestData { public static List<CDataItem> TestData { get; set; } static CTestData() { TestData = new List<CDataItem>(); TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "Chinese", Score = 10.0 }); TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "English", Score = 20.0 }); TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "Math", Score = 30.0 }); TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "Chinese", Score = 40.0 }); TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "English", Score = 50.0 }); TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "Math", Score = 60.0 }); TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "Chinese", Score = 70.0 }); TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "English", Score = 80.0 }); TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "Math", Score = 90.0 }); TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Chinese", Score = 100.0 }); TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "English", Score = 110.0 }); TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Math", Score = 120.0 }); TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Math", Score = 125.0 }); TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "Chinese", Score = 130.0 }); TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "English", Score = 140.0 }); TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "Math", Score = 150.0 }); TestData.Add(new CDataItem() { Name = "I", Age="50Y", Course = "Chinese", Score = 160.0 }); TestData.Add(new CDataItem() { Name = "I", Age = "50Y", Course = "Chinese", Score = 165.0 }); TestData.Add(new CDataItem() { Name = "You", Age = "60Y", Course = "English", Score = 170.0 }); TestData.Add(new CDataItem() { Name = "You", Age = "60Y", Course = "English", Score = 175.0 }); } } public class CDataItem { public string Name { get; set; } public string Course { get; set; } public double Score { get; set; } public string Age { get; set; } }
//Title Column DisplayDataGrid.Columns.Add(new DataGridTextColumn() { Header = CrossHeader, HeaderStyle = CrossHeaderStyle, Binding = new Binding() { Path = new PropertyPath(""), }, CellStyle = TitleCellStyle, IsReadOnly = true, }); //新增加需要显示的Age Column DisplayDataGrid.Columns.Add(new DataGridTextColumn() { Header="Age", Binding = new Binding() { Path = new PropertyPath("Age"), }, IsReadOnly = true, });
期望结果:
Age Chinese English Math
TFSoft1 10 20 30
TFSoft2 40 50 60
TFSoft3 70 80 90
TFSoft4 100 110 120
TFSoft5 130 140 150
I 50Y 160
You 60Y 170
-
前几天无法登录论坛,未能及时回答,现回答如下:
应该指出的是,数据值 可以取平均,最大,最小,第一个,最后一个。
1)xaml
<UserControl
x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"><UserControl.Resources>
<Style
x:Name="CssYTitleHeader"
TargetType="sdk:DataGridColumnHeader">
<Setter
Property="Foreground"
Value="Green">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Center">
</Setter>
<Setter
Property="FontWeight"
Value="Bold">
</Setter>
</Style>
<Style
x:Name="CssXTitleHeader"
TargetType="sdk:DataGridColumnHeader">
<Setter
Property="Foreground"
Value="Red">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Center">
</Setter>
<Setter
Property="FontWeight"
Value="Bold">
</Setter>
</Style>
<Style
x:Name="CssYTitleCell"
TargetType="sdk:DataGridCell">
<Setter
Property="Foreground"
Value="Green">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Left">
</Setter>
</Style>
<Style
x:Name="CssValueCell"
TargetType="sdk:DataGridCell">
<Setter
Property="Foreground"
Value="Blue">
</Setter>
<Setter
Property="HorizontalContentAlignment"
Value="Right">
</Setter>
</Style>
</UserControl.Resources><!-- Test Data Grid, Required When Testing -->
<Grid
x:Name="GrdRoot">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Vertical">
<sdk:DataGrid
x:Name="DgrTest"
Width="600"
Height="300" />
<Button
x:Name="CmdShow"
Content="Show Corss Data"></Button>
</StackPanel>
</Grid>
</UserControl>2)cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.CmdShow.Click += CmdShow_Click;
}private void CmdShow_Click(object sender, RoutedEventArgs e)
{
var X = new T4CrossViewHelperEx()
{
//Required Parameters
DataSource = CTestData.TestData,
DisplayDataGrid = this.DgrTest,
YTitlePropertyNames = "Name,Age",
XTitlePropertyName = "Course",
ValuePropertyName = "Score",
//Optional Parameters
YTitlePropertyCaptions = "NameEx,AgeEx",
ValueFormat = "#0.0",
ValueFindMode = T4CrossViewHelperEx.EValueFindMode.Average,
ValueCellStyle = this.CssValueCell,
YTitleCellStyle = this.CssYTitleCell,
YHeaderStyle = this.CssYTitleHeader,
XHeaderStyle = this.CssXTitleHeader,
};
X.InitDataGrid();
}
public static class CTestData
{
public static List<CDataItem> TestData { get; set; }
static CTestData()
{
TestData = new List<CDataItem>();
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "Chinese", Score = 10.0 });
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "English", Score = 20.0 });
TestData.Add(new CDataItem() { Name = "TFSoft1", Course = "Math", Score = 30.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "Chinese", Score = 40.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "English", Score = 50.0 });
TestData.Add(new CDataItem() { Name = "TFSoft2", Course = "Math", Score = 60.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "Chinese", Score = 70.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "English", Score = 80.0 });
TestData.Add(new CDataItem() { Name = "TFSoft3", Course = "Math", Score = 90.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Chinese", Score = 100.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "English", Score = 110.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Math", Score = 120.0 });
TestData.Add(new CDataItem() { Name = "TFSoft4", Course = "Math", Score = 125.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "Chinese", Score = 130.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "English", Score = 140.0 });
TestData.Add(new CDataItem() { Name = "TFSoft5", Course = "Math", Score = 150.0 });
TestData.Add(new CDataItem() { Name = "I", Age = "50Y", Course = "Chinese", Score = 160.0 });
TestData.Add(new CDataItem() { Name = "I", Age = "50Y", Course = "Chinese", Score = 165.0 });
TestData.Add(new CDataItem() { Name = "You", Age = "60Y", Course = "English", Score = 170.0 });
TestData.Add(new CDataItem() { Name = "You", Age = "60Y", Course = "English", Score = 175.0 });
}
}
public class CDataItem
{
public string Name { get; set; }
public string Course { get; set; }
public double Score { get; set; }
public string Age { get; set; }
}/// <summary>
/// T4CrossViewHelperEx
/// </summary>
public class T4CrossViewHelperEx
{
/// <summary>
/// DataSource, Required
/// </summary>
public IEnumerable DataSource { get; set; }/// <summary>
/// DisplayDataGrid, Required
/// </summary>
public DataGrid DisplayDataGrid { get; set; }/// <summary>
/// XTitlePropertyName, Required
/// </summary>
public string XTitlePropertyName { get; set; }/// <summary>
/// YTitlePropertyNames, Required
/// </summary>
public string YTitlePropertyNames { get; set; }/// <summary>
/// ValuePropertyName, Required
/// </summary>
public string ValuePropertyName { get; set; }/// <summary>
/// YTitlePropertyCaptions, Optional
/// </summary>
public string YTitlePropertyCaptions { get; set; }/// <summary>
/// XHeaderStyle, Optional
/// </summary>
public Style XHeaderStyle { get; set; }/// <summary>
/// YHeaderStyle, Optional
/// </summary>
public Style YHeaderStyle { get; set; }/// <summary>
/// YTitleCellStyle, Optional
/// </summary>
public Style YTitleCellStyle { get; set; }/// <summary>
/// ValueCellStyle, Optional
/// </summary>
public Style ValueCellStyle { get; set; }/// <summary>
/// ValueFormat, Optional
/// </summary>
public string ValueFormat { get; set; }/// <summary>
/// ValueFindMode, Optional
/// </summary>
public EValueFindMode ValueFindMode { get; set; }/// <summary>
/// InitDataGrid
/// </summary>
public void InitDataGrid()
{DisplayDataGrid.ItemsSource = null;
DisplayDataGrid.AutoGenerateColumns = false;
DisplayDataGrid.Columns.Clear();var LnqYData = (from X in DataSource.Cast<object>()
let X1 = GetDataItemValues(X, YTitlePropertyNames)
select X1).Distinct(new CDictEQ());
//YTitle Columns
if (1 == 1)
{
var A1 = YTitlePropertyNames.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
var A2 = new string[] { };
if (!string.IsNullOrWhiteSpace(YTitlePropertyCaptions))
{
A2 = YTitlePropertyCaptions.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
}
var Lnq = from X in Enumerable.Range(0, A1.Length)
let XPath = "[" + A1[X] + "]"
let XHeader = X < A2.Length ? A2[X] : A1[X]
select new { Path = XPath, Header = XHeader };
foreach (var Itm in Lnq)
{
DisplayDataGrid.Columns.Add(new DataGridTextColumn()
{
IsReadOnly = true,
Header = Itm.Header,
HeaderStyle = YHeaderStyle,
Binding = new Binding(Itm.Path),
CellStyle = YTitleCellStyle,
});
};
}
//Value Column
if (1 == 1)
{
var LnqXData = (from X in DataSource.Cast<object>()
let X1 = GetDataItemValue(X, XTitlePropertyName)
orderby X1
select X1).Distinct();
foreach (var Itm in LnqXData)
{
DisplayDataGrid.Columns.Add(new DataGridTextColumn()
{
IsReadOnly = true,
Header = Itm,
HeaderStyle = XHeaderStyle,
Binding = new Binding()
{
Path = new PropertyPath(""),
StringFormat = ValueFormat,
Converter = new CValueConverter()
{
DataSource = DataSource,
XTitlePropertyName = XTitlePropertyName,
ValuePropertyName = ValuePropertyName,
ValueFindMode = ValueFindMode,
},
ConverterParameter = Itm,
},
CellStyle = ValueCellStyle,
});
}
}
DisplayDataGrid.ItemsSource = LnqYData;
}/// <summary>
/// CDictEQ, Called Only By T4CrossViewHelper
/// </summary>
public class CDictEQ : IEqualityComparer<Dictionary<string, object>>
{
public bool Equals(Dictionary<string, object> DicA, Dictionary<string, object> DicB)
{
var Rlt = false;
if (DicA == null || DicB == null)
{
Rlt =
((DicA == null && DicB != null) || (DicA != null && DicB == null)) ?
false : true;
}
else
{
var Lnq = from X in DicA.Keys
where !ObjEq(DicA[X], DicB[X])
select X;
Rlt = Lnq.Count() > 0 ? false : true;
}
return Rlt;
}private bool ObjEq(object O1, object O2)
{
var Rlt = false;
if (O1 == null || O2 == null)
{
Rlt =
((O1 == null && O2 != null) || (O1 != null && O2 == null)) ?
false : true;
}
else
{
Rlt = O1.Equals(O2) ? true : false;
}
return Rlt;
}public int GetHashCode(Dictionary<string, object> Dic)
{
var Rlt = 0;
var Lnq = from X in Dic.Keys
let X1 = Dic[X]
let X2 = X1 == null ? 0 : X1.GetHashCode()
select X2;
foreach (var Itm in Lnq) { Rlt = Rlt ^ Itm; }; return Rlt;
}
}/// <summary>
/// CValueConverter, Called Only By T4CrossViewHelper
/// </summary>
public class CValueConverter : IValueConverter
{
public IEnumerable DataSource { get; set; }
public string XTitlePropertyName { get; set; }
public string ValuePropertyName { get; set; }
public EValueFindMode ValueFindMode { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var YValue = value as Dictionary<string, object>;
var XValue = parameter;
var Lnq = from X in DataSource.Cast<object>()
let X1 = GetDataItemValues(X, string.Join(",", YValue.Keys))
where (new CDictEQ()).Equals(YValue, X1)
let X2 = GetDataItemValue(X, XTitlePropertyName)
where (X2 == null && XValue == null) || (X2 != null && X2.Equals(XValue))
let X3 = GetDataItemValue(X, ValuePropertyName)
select X3;
var Rlt = Lnq.FirstOrDefault();
switch (ValueFindMode)
{
case EValueFindMode.First: break;
case EValueFindMode.Last: Rlt = Lnq.Last(); break;
case EValueFindMode.Average: if (Rlt != null) { Rlt = Lnq.Average(lX => (double)lX); }; break;
case EValueFindMode.Min: Rlt = Lnq.Min(); break;
case EValueFindMode.Max: Rlt = Lnq.Max(); break;
}
return Rlt;
}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}/// <summary>
/// EValueFindMode
/// </summary>
public enum EValueFindMode
{
First = 0, Last = 1, Average = 2, Min = 3, Max = 4
}/// <summary>
/// GetDataItemValues
/// </summary>
/// <param name="DataItem"></param>
/// <param name="PropNames"></param>
/// <returns></returns>
private static Dictionary<string, object> GetDataItemValues(object DataItem, string PropNames)
{
var Lnq = from X in PropNames.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)
let XKey = X
let XValue = GetDataItemValue(DataItem, X)
select new { Key = XKey, Value = XValue };
var Rlt = Lnq.ToDictionary(lX => lX.Key, lX => lX.Value); return Rlt;
}/// <summary>
/// GetDataItemValue
/// </summary>
/// <param name="DataItem"></param>
/// <param name="PropName"></param>
/// <returns></returns>
private static object GetDataItemValue(object DataItem, string PropName)
{
var Lnq = from X in DataItem.GetType().GetProperties()
where X.Name.Trim().ToUpper() == PropName.Trim().ToUpper()
select X.GetValue(DataItem, null);
var Rlt = Lnq.FirstOrDefault(); return Rlt;
}
}
}
}
- 已标记为答案 Anton Jin 2011年6月17日 5:37