我想创建一个新列,然后在按钮点击事件中将值添加到 该新列。那可能吗?该列可能在其下方有几行,具体取决于报价中的项目数量。
到目前为止我取得的成就:
我的课程,我的所有信息都存储在
中public class ViewQuoteItemList
{
...
public double SupplierCost { get; set; }
...
}
我可以创建我的列并将其绑定到我的ViewQuoteItemList
类
DataGridTextColumn columnFeedbackSupplier = new DataGridTextColumn();
columnFeedbackSupplier.Binding = new Binding("SupplierCost");
//The header of the column gets it's value from a combobox where you select a company to be added to the datagrid
columnFeedbackSupplier.Header = (cmbFeedbackSelectSupplier.SelectedItem as DisplayItems).Name;
从这里我从不同的数据网格中获取我的引用项目,然后将它们添加到我想要添加新列及其值的第二个数据网格中
IList list = dgFeedbackAddCost.SelectedItems as IList;
IEnumerable<ViewQuoteItemList> items = list.Cast<ViewQuoteItemList>();
var collection = (from i in items
let a = new ViewQuoteItemList { SupplierCost = 0 }
select a).ToList();
最后,我将新列添加到第二个数据网格,并将collection
设置为datagrid的ItemSource
dgFeedbackSelectSupplier.Columns.Add(columnFeedbackSupplier);
dgFeedbackSelectSupplier.ItemsSource = collection;
我的问题是,一旦我从其中一个供应商编辑数据单元格,整个行就会更新一个值,因为它全部绑定到一个类/项目源。这可以解决吗?
修改
“整行更新”意味着每次我将值插入一行中的一个单元格时,该行中的每个单元格都会使用相同的值进行更新。这是一些显示我的意思的图片。我想编辑所有数据,这一切都发生在我的第二个数据网格(dgFeedbackSupplier)上。
在这里,我有两家公司添加了我要比较价格的4个项目。现在,我想点击公司下面的单个单元格,并为某个项目添加一个值。
然后,当我更改所选单元格中的值时,同一行中该特定项目的每个其他公司的值都会使用相同的值进行更新。
这是我的问题,我只需更改一个单元格的值,而不是整行。
编辑2:
如何将此collection
转换为ExpandoObject
?
var collection = (from i in items
let a = new ViewQuoteItemList { Item = i.Item, Supplier = 25 }
select a).ToList();
编辑3:
我的XAML:
<DataGrid x:Name="dgFeedbackSelectSupplier" Margin="245,266,0,32" BorderBrush="#FFADADAD" ColumnWidth="*" AutoGenerateColumns="True" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn x:Name="columnFeedbackSupplierItem" IsReadOnly="True" Header="Item" Binding="{Binding Item}"/>
</DataGrid.Columns>
</DataGrid>
这就是我的整个方法在我添加列的时刻以及从其他数据网格中获取项目的方式:
private void btnFeedbackSelectSupplier_Click(object sender, RoutedEventArgs e)
{
supplier.Id = (cmbFeedbackSelectSupplier.SelectedItem as DisplayItems).Id;//Not using yet
supplier.Name = (cmbFeedbackSelectSupplier.SelectedItem as DisplayItems).Name;
DataGridTextColumn columnFeedbackSupplier = new DataGridTextColumn();
columnFeedbackSupplier.Binding = new Binding("Supplier") { Mode = BindingMode.TwoWay };
columnFeedbackSupplier.CanUserReorder = true;
columnFeedbackSupplier.CanUserResize = true;
columnFeedbackSupplier.IsReadOnly = false;
columnFeedbackSupplier.Header = supplier.Name;
dgFeedbackAddCost.SelectAll();
IList list = dgFeedbackAddCost.SelectedItems as IList;
IEnumerable<ViewQuoteItemList> items = list.Cast<ViewQuoteItemList>();
var collection = new List<ExpandoObject>();
foreach (var i in items)
{
dynamic a = new ExpandoObject();
a.Id = (cmbFeedbackSelectSupplier.SelectedItem as DisplayItems).Id;
a.Item = i.Item;
a.Supplier = 25;
collection.Add(a);
}
dgFeedbackSelectSupplier.Columns.Add(columnFeedbackSupplier);
dgFeedbackSelectSupplier.ItemsSource = collection;
}
答案 0 :(得分:3)
我可以提出另一种方法吗?根据我的理解;
您有供应商和这些供应商有物品。您可以添加新供应商。我认为供应商可能没有所有项目(对于挑战:))。
您希望以类似于视图的网格呈现此数据结构。
这里的问题是您尝试使用表格视图组件显示非表格数据。你拥有的是分层数据。在继续我的解决方案之前,这里有一些屏幕截图。
我在这里基本上做的是创建关于分层数据的新视图,填补空白并将其转换为表格形式。我在空插槽中使用了假类,因此我可以轻松地在XAML中选择正确的数据模板。我避免使用任何自定义代码并将所有内容保存在MVVM + XAML中。所以绑定和预期的工作。
当集合发生变化时,必须更新新视图,因此我使用了MVVMLight中的messenger类来实现,并手动调用了RaisePropertyChanged事件。
在XAML中,我使用ItemsControl和UniformGrid组件来创建像视图一样的网格。
我将完整的解决方案放在GitHub:https://github.com/orhtun/GridLikeViewWithDynamicColumns
上它会在每次运行时创建随机数据。如果出现构建错误,请尝试右键单击解决方案并恢复NuGet包。
答案 1 :(得分:0)
您无法使用集合与第二个DataGrid绑定,因为您的视图是动态的,可以包含变量no列。
您应该使用DataTable作为DataGrid的源。不是在网格中添加列,而是在DataTable中添加一列,并在Grid中自动生成该列。
将项目源(任何类型)转换为DataTable的方法是(可能是第一次需要):
public static DataTable DataGridtoDataTable(DataGrid dg)
{
dg.SelectAllCells();
dg.ClipboardCopyMode = DataGridClipboardCopyMode.IncludeHeader;
ApplicationCommands.Copy.Execute(null, dg);
dg.UnselectAllCells();
String result = (string)Clipboard.GetData(DataFormats.CommaSeparatedValue);
string[] Lines = result.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
string[] Fields;
Fields = Lines[0].Split(new char[] { ',' });
int Cols = Fields.GetLength(0);
DataTable dt = new DataTable();
for (int i = 0; i < Cols; i++)
dt.Columns.Add(Fields[i].ToUpper(), typeof(string));
DataRow Row;
for (int i = 1; i < Lines.GetLength(0) - 1; i++)
{
Fields = Lines[i].Split(new char[] { ',' });
Row = dt.NewRow();
for (int f = 0; f < Cols; f++)
{
Row[f] = Fields[f];
}
dt.Rows.Add(Row);
}
return dt;
}
然后当您必须在DataGrid中添加列时,通过迭代collection
来填充表中的列以填充数据表中的列。
没有简单的方法来解决您的问题,因为您的方案是独特的,只有动态结构才能满足您的需求。
由于使用DataTable,您的所有单元格都将绑定到唯一的实体。 DataGrid单元格的单个更改只会更新一个单元格。(与多个单元格绑定到同一属性的集合不同)
答案 2 :(得分:0)
根据您的要求,我建议您使用Microsoft Dynamics
ExpandoObject
您需要创建一个List<ExpandoObject>
,它只是一个Dictionary<string,object>
,其中您的密钥是您的属性名称,对象就是您的价值。所以在你的情况下,
ViewQuoteItem
中的所有属性都会添加到此新对象中,当您需要添加列时,可以向对象添加另一个属性。然后只需更新您的视图并查看添加到网格的新列。
要使用Expando,您可以轻松实现 -
var dynamicItem = New ExpandoObject();
dynamicItem.Item = "Test";
dynamicItem.BarlwoodCityDeep = (int)350;
或者你可以将dynamicItem视为这样的字典 -
IDictionary<String, Object> dynamicDict = dynamicItem
dynamicDict.Add("MyNewProperty","MySomeValue")
我个人觉得转换为Dict
很容易,因为它让我可以灵活地显式添加属性,然后使用键来引用它们,但它只是一种轻松而不是强制。
我还建议您使用一种方法将dataList映射到新的expandoList并将expandlist绑定到您的视图,请确保在WPF中使用AutoGeneration列,以便新添加的列可见。
你可以看一下我的解决方案here,它在某种类似的情况下对我有用。
如果您是dynamics
的新手,您可能会发现它有点棘手但是Expandos可以使用并轻松使用它们很棒。
从ViewQuoteItemList转换为Expando -
var collection = new List<ExpandoObject>();
foreach (var i in items)
{
dynamic a = new ExpandoObject();
a.Item = i.item;
a.Supplier = 25;
collection.Add(a);
}
答案 3 :(得分:0)
就个人而言,我会远离实际实例化单个列,而是直接将它们添加到DataGridView,然后操纵它们的属性。
List<MyClass> myList = new List<MyClass>();
BindingList<MyClass> bList = new BindingList<MyClass>(myList);
myDataGridView.DataSource = new BindingSource(bList,null);
//Now Lets add a custom column..
myDataGridView.Columns.Add("Text","Text");
//Now lets edit it's properties
myDataGridView.Columns["Text"].ReadOnly = false;
myDataGridView.EditMode = DataGridViewEditMode.EditOnKeystroke;
//Now lets walk through and throw some data in each cell..
if(myDataGridView.Rows.Count > 1)
{
for(int i = 0;i < myDataGridView.Rows.Count;i++)
{
myDataGridView.Rows[i].Cells["Text"].Value = "My Super Useful Text";
}
}
避免使用实例化列,然后添加它在过去帮助我解决奇怪的链接问题,例如编辑一个单元格,其他更改。至于子视图等,我不能说我可以就此发表评论。
答案 4 :(得分:0)
我看到这个问题引起了很多关注,所以我会将解决方案发布到我的答案中。我希望这可以帮助那些人了解如何仅将数据添加到特定列。 :)
正如旁注 - 这是我创建的测试应用程序,因此编码与我原始问题中的编码不同。我还用字典解决了我的问题。它很棒!
创建我的物料和供应商清单:
//I create my dummy suppliers
private string[] CONST_Supplies = { "Supplier 1", "Supplier 2", "Supplier 3", "Supplier 4" };
public MainWindow()
{
InitializeComponent();
//I add my dummy items into my datagrid
//These are the items that I want to compare prices with
List<ViewQuoteItemList> list = new List<ViewQuoteItemList>();
list.Add(new ViewQuoteItemList() { Item = "Item 1" });
list.Add(new ViewQuoteItemList() { Item = "Item 2" });
list.Add(new ViewQuoteItemList() { Item = "Item 3" });
list.Add(new ViewQuoteItemList() { Item = "Item 4" });
list.Add(new ViewQuoteItemList() { Item = "Item 5" });
list.Add(new ViewQuoteItemList() { Item = "Item 6" });
//Loading the items into the datagrid on application start
DataGridTest.ItemsSource = list;
//Adding my dummy suppliers to my supplier selection combobox
foreach (var supplier in CONST_Supplies)
ComboBoxTest.Items.Add(supplier);
}
我的按钮点击事件:
private void Add_Click(object sender, RoutedEventArgs e)
{
//Select my supplier from my Supplier's combobox
var supplier = ComboBoxTest.SelectedItem as string;
//Create the Supplier column and bind it to my 'ViewQuoteItemList' class +
//I'm binding it to the unique supplier selected from my combobox
DataGridTextColumn columnFeedbackSupplier = new DataGridTextColumn();
columnFeedbackSupplier.Binding = new Binding("Suppliers[" + supplier + "]");
columnFeedbackSupplier.Binding.FallbackValue = "Binding failed";
columnFeedbackSupplier.CanUserReorder = true;
columnFeedbackSupplier.CanUserResize = true;
columnFeedbackSupplier.IsReadOnly = false;
columnFeedbackSupplier.Header = ComboBoxTest.SelectedItem as string;
foreach (var item in DataGridTest.ItemsSource as List<ViewQuoteItemList>)
if (!item.Suppliers.ContainsKey(supplier))
item.Suppliers.Add(supplier, string.Empty);
DataGridTest.Columns.Add(columnFeedbackSupplier);
}
我的课程:
public class ViewQuoteItemList
{
public ViewQuoteItemList()
{
Suppliers = new ObservableDictionary<string, string>();
}
public int Id { get; set; }
public string Item { get; set; }
public ObservableDictionary<string, string> Suppliers { get; set; }
}
我的Observable Dictionary,其中包括很多工作:
public class ObservableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged
{
private const string CountString = "Count";
private const string IndexerName = "Item[]";
private const string KeysName = "Keys";
private const string ValuesName = "Values";
private IDictionary<TKey, TValue> _Dictionary;
protected IDictionary<TKey, TValue> Dictionary
{
get { return _Dictionary; }
}
#region Constructors
public ObservableDictionary()
{
_Dictionary = new Dictionary<TKey, TValue>();
}
public ObservableDictionary(IDictionary<TKey, TValue> dictionary)
{
_Dictionary = new Dictionary<TKey, TValue>(dictionary);
}
public ObservableDictionary(IEqualityComparer<TKey> comparer)
{
_Dictionary = new Dictionary<TKey, TValue>(comparer);
}
public ObservableDictionary(int capacity)
{
_Dictionary = new Dictionary<TKey, TValue>(capacity);
}
public ObservableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
{
_Dictionary = new Dictionary<TKey, TValue>(dictionary, comparer);
}
public ObservableDictionary(int capacity, IEqualityComparer<TKey> comparer)
{
_Dictionary = new Dictionary<TKey, TValue>(capacity, comparer);
}
#endregion
#region IDictionary<TKey,TValue> Members
public void Add(TKey key, TValue value)
{
Insert(key, value, true);
}
public bool ContainsKey(TKey key)
{
return Dictionary.ContainsKey(key);
}
public ICollection<TKey> Keys
{
get { return Dictionary.Keys; }
}
public bool Remove(TKey key)
{
if (key == null) throw new ArgumentNullException("key");
TValue value;
Dictionary.TryGetValue(key, out value);
var removed = Dictionary.Remove(key);
if (removed)
//OnCollectionChanged(NotifyCollectionChangedAction.Remove, new KeyValuePair<TKey, TValue>(key, value));
OnCollectionChanged();
return removed;
}
public bool TryGetValue(TKey key, out TValue value)
{
return Dictionary.TryGetValue(key, out value);
}
public ICollection<TValue> Values
{
get { return Dictionary.Values; }
}
public TValue this[TKey key]
{
get
{
return Dictionary[key];
}
set
{
Insert(key, value, false);
}
}
#endregion
#region ICollection<KeyValuePair<TKey,TValue>> Members
public void Add(KeyValuePair<TKey, TValue> item)
{
Insert(item.Key, item.Value, true);
}
public void Clear()
{
if (Dictionary.Count > 0)
{
Dictionary.Clear();
OnCollectionChanged();
}
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return Dictionary.Contains(item);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
Dictionary.CopyTo(array, arrayIndex);
}
public int Count
{
get { return Dictionary.Count; }
}
public bool IsReadOnly
{
get { return Dictionary.IsReadOnly; }
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
return Remove(item.Key);
}
#endregion
#region IEnumerable<KeyValuePair<TKey,TValue>> Members
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return Dictionary.GetEnumerator();
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)Dictionary).GetEnumerator();
}
#endregion
#region INotifyCollectionChanged Members
public event NotifyCollectionChangedEventHandler CollectionChanged;
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public void AddRange(IDictionary<TKey, TValue> items)
{
if (items == null) throw new ArgumentNullException("items");
if (items.Count > 0)
{
if (Dictionary.Count > 0)
{
if (items.Keys.Any((k) => Dictionary.ContainsKey(k)))
throw new ArgumentException("An item with the same key has already been added.");
else
foreach (var item in items) Dictionary.Add(item);
}
else
_Dictionary = new Dictionary<TKey, TValue>(items);
OnCollectionChanged(NotifyCollectionChangedAction.Add, items.ToArray());
}
}
private void Insert(TKey key, TValue value, bool add)
{
if (key == null) throw new ArgumentNullException("key");
TValue item;
if (Dictionary.TryGetValue(key, out item))
{
if (add) throw new ArgumentException("An item with the same key has already been added.");
if (Equals(item, value)) return;
Dictionary[key] = value;
OnCollectionChanged(NotifyCollectionChangedAction.Replace, new KeyValuePair<TKey, TValue>(key, value), new KeyValuePair<TKey, TValue>(key, item));
}
else
{
Dictionary[key] = value;
OnCollectionChanged(NotifyCollectionChangedAction.Add, new KeyValuePair<TKey, TValue>(key, value));
}
}
private void OnPropertyChanged()
{
OnPropertyChanged(CountString);
OnPropertyChanged(IndexerName);
OnPropertyChanged(KeysName);
OnPropertyChanged(ValuesName);
}
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private void OnCollectionChanged()
{
OnPropertyChanged();
if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair<TKey, TValue> changedItem)
{
OnPropertyChanged();
if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, changedItem));
}
private void OnCollectionChanged(NotifyCollectionChangedAction action, KeyValuePair<TKey, TValue> newItem, KeyValuePair<TKey, TValue> oldItem)
{
OnPropertyChanged();
if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItem, oldItem));
}
private void OnCollectionChanged(NotifyCollectionChangedAction action, IList newItems)
{
OnPropertyChanged();
if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItems));
}
}
我知道这是很多代码。对不起,我没有时间解释一切以及它是如何工作的。我希望你们能够自己解决这个问题;)课堂上还有很多额外的功能可以用于各种目的。
最后,这是我的XAML:
<Button x:Name="Add" Content="Add" HorizontalAlignment="Left" Margin="65,143,0,0" VerticalAlignment="Top" Width="75" Click="Add_Click"/>
<DataGrid x:Name="DataGridTest" CanUserAddRows="False" AutoGenerateColumns="False" HorizontalAlignment="Left" Margin="165,115,0,0" VerticalAlignment="Top" Height="279" Width="611" ColumnWidth="*">
<DataGrid.Columns>
<DataGridTextColumn x:Name="columnFeedbackSupplierItem" Header="Item" Binding="{Binding Item}"/>
</DataGrid.Columns>
</DataGrid>
<ComboBox x:Name="ComboBoxTest" HorizontalAlignment="Left" Margin="20,115,0,0" VerticalAlignment="Top" Width="120"/>
注 - 双击单元格时,可以编辑datagrid中的值。感谢所有加入我的问题或帮助我朝正确方向前进的人。我希望这可以帮助那些人。