2016-02-05 43 views
5

我想創建一個新列,然後將值添加到只有表示按鈕單擊事件上的新列。那可能嗎?該列可能在其下面有幾行,具體取決於引用中的項目數量。將數據添加到DataGrid中的特定列

到目前爲止,我所取得的成就:

我的課堂,我的所有的信息都存儲在

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(); 

最後,我的新列添加到第二個DataGrid,並設置collection作爲DataGrid的ItemSource

dgFeedbackSelectSupplier.Columns.Add(columnFeedbackSupplier); 
dgFeedbackSelectSupplier.ItemsSource = collection; 

我的問題是,一旦我從供應商之一編輯數據的單元格,整行被更新爲一個值,因爲它全部綁定到一個類/項源。這可以解決嗎?

編輯:

「整排被更新」是指每次我值插入一個細胞在一排的時候,該行中的每一個細胞被以相同的值更新。這裏有一些照片顯示我的意思。我想編輯所有的數據,這一切都發生在我的第二個數據網格(dgFeedbackSupplier)。

在這裏,我有兩個公司添加了4件商品,我想比較價格。現在我想單擊公司下面的單個單元格併爲某個項目添加值。

enter image description here

這裏我雙擊單元格編輯/更改值。 enter image description here

然後,當我在所選單元格中更改我的值時,同一行中該特定項目的每個其他公司的值都會使用相同的值進行更新。 enter image description here

這是我的問題,我需要只改變一個單元格的值,而不是整行。

編輯2:

我怎麼能轉換這個collectionExpandoObject

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

對不起,我不明白。 「整行更新」是什麼意思?你編輯哪個單元會產生問題?在哪個datagrid?你正在添加或編輯數據?你的「按鈕」的行爲是什麼?在我看來,你需要拋光的問題 – tede24

+0

@ tede24感謝評論人。我已經編輯了我的問題以提供更多細節,我希望你能理解我想要做的更好一點。 – CareTaker22

+0

您的兩列已綁定到ViewQuoteItemList類的相同屬性? –

回答

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; } 
} 

而我可觀察字典裏很多工作發生:

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中的值可以當你在雙擊單元格進行編輯。感謝所有加入我的問題或幫助我朝正確方向發展的人士。我希望這可以幫助那裏的人。

0

您不能使用集合與第二個DataGrid綁定,因爲您的視圖是動態的,可以具有變量no列。

您應該使用數據表作爲源到您的DataGrid。不要在網格中添加列,而要在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; 

    } 

後來當你必須在數據網格添加列,添加一列通過迭代上collection表填寫數據表中的列。

有沒有簡單的方法做你的問題,你的情況是獨特的,唯一的動態結構可以fullfill您的需要。

由於使用的DataTable所有的細胞將被綁定到獨特的實體。只有一個單元格將得到更新DataGrid單元格的一個變化。(不像集合,其中多個單元綁定到同一屬性)

+0

謝謝你的答案!我會盡快更新你的進度;) – CareTaker22

+0

全局剪貼板數據在此操作過程中被修改。 在操作之前彈出當前剪貼板數據並將其推回剪貼板會更好。 –

0

對於您的要求,我建議你使用Microsoft DynamicsExpandoObject

你需要創建一個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並將擴展列表綁定到你的視圖,請確保你使用WPF中的列自動生成,以便新添加的列是可見的。

你可以看看我的解決方案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); 
      } 

相關文章here和另一個有趣的一個here

+0

謝謝你的答案!我會盡快讓你知道一切工作。 – CareTaker22

+0

希望它適用於你;) – Muds

+0

這ExpandoObjects真的很酷(或我迄今爲止學到的東西),但我正在努力的一件事是這樣的:_「ViewQuoteItem中的所有屬性都被添加到這個新的對象「_。我怎樣才能將我的'ViewQuoteItemList'設置爲'ExpandoObject'? 0_o – CareTaker22

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"; 
    } 
} 

避免使用實例之列,然後加入它幫助我在與怪異的聯動問題的過去,例如編輯一個單元,以及其他改變。至於子視圖等,我不能說我可以評論很多。

3

我可以提出另一種方法嗎?根據我的理解,

你有供應商和這些供應商有物品。您可以添加新的供應商。我認爲供應商可能沒有全部物品(挑戰:))。

你想要像視圖一樣在網格中呈現這個數據結構。

這裏的問題是,您正在嘗試使用表格視圖組件顯示非表格數據。你有什麼是分層數據。在繼續我的解決方案之前,這裏有一些屏幕截圖。

enter image description here

enter image description here

enter image description here

我基本上在這裏做什麼,以創建分層數據的新看法,填補國內空白,把它變成一個表格形式。我使用假類作爲空插槽,以便我可以輕鬆地在XAML中選擇適當的數據模板。我避免使用任何自定義代碼並以MVVM + XAML方式保存所有內容。所以綁定和預期的這樣的作品。

集合發生變化時,必須更新新視圖,因此我使用MVVMLight中的messenger類實現輕鬆實現,並手動調用RaisePropertyChanged事件。

在XAML中,我使用ItemsControl和UniformGrid組件來創建類似視圖的網格。

我把GitHub完整的解決方案:https://github.com/orhtun/GridLikeViewWithDynamicColumns

它創建每次運行的隨機數據。如果出現構建錯誤,請嘗試右鍵單擊解決方案並恢復NuGet包。

+0

嗨!並感謝您的回答。這太遲了。我想出瞭如何在我的數據網格中做到這一點。我會在今天晚些時候發佈答案,當我有機會的時候!再次感謝您的所有努力。 :) – CareTaker22

+0

沒問題,這是一個有趣的問題。無論如何,想要在將來可能需要它:) –

+0

甜美的男人!我發佈了一個答案,我展示了我的編碼以及我如何解決這個謎題。希望它能在未來幫助你。 – CareTaker22

相關問題