所以我陷入了一個問題,我能夠更新數據網格中的值,當文本框編輯數據網格的選擇單元格的值時,這會立即導致UI更新。 Pitfal是我不能更新依賴於這個單元格值的任意單元格。單元格/列綁定到的數據更改DataGrid不更新依賴單元格值。我有很多單元,所以調用DataGrid.Item.Refresh()的代價非常高。我試圖創建一個只引發InotifyProperty更改事件的方法,但這不會導致網格中的更新。我不知道如何強制更新GUI。DataGrid只更新選定的單元格
模型單元的代碼如下。並在其下面標識代碼。
public class ModelCell : INotifyPropertyChanged {
//This is a class that represents a cell that a user clicks on. it contains few items. And should have a reference to the SpreadSheet object
public String CellName {
get;
set;
}
public IEnumerable<String> dependents {
get;
private set;
}
public String Contents {
get {
return Host.GetCellContents(CellName);
}
set {
if (value != _contents) {
IEnumerable<String> tmpDep = Host.SetCellContents(CellName, value);
try {
if (Host.GetCellValue(CellName) is SS.FormulaError) {
//Revert the change.
Host.SetCellContents(CellName, _contents);
} else {
_contents = value;
NotifyPropertyChanged("Contents");
NotifyPropertyChanged("Value");
//Next is to notify dependents that we have changed. Since the names will be in the Format of A1
this.dependents = tmpDep;
}
} catch (Exception e) {
//We got an exception no change was made to the sheet anyway.
MessageBox.Show(e.Message);
}
} else NotifyPropertyChanged("Value");
}
}
public int Row;
public int Col;
public override string ToString() {
return "THis is a test!";
}
/// <summary>
/// Default initialize the empty cell to empty contents. this makes the construction of the objects simpler;
/// </summary>
private String _contents = "";
/// <summary>
/// This value is contained in the SpreadSheet so it is automatically changed with the Contents.
/// </summary>
public String Value {
get {
try {
Object returned = Host.GetCellValue(CellName);
if (returned is String || returned is Double)
return returned.ToString();
return ((SS.FormulaError)returned).Reason;
} catch (Exception e) {
MessageBox.Show("Cell " + this.CellName + " encountered an exception getting the value: " + e.Message);
return "";
}
}
set {
//instead assign contents
NotifyPropertyChanged("Value");
}
}
public SS.Spreadsheet Host {
set;
private get;
}
/// <summary>
/// Creates an empty cell with no value or contents with the specified name.
/// </summary>
/// <param name="Name">The Name of this cell generally in the format [A-Z][1-99]</param>
public ModelCell (String Name) {
this.CellName = Name;
}
public ModelCell() {
//Name will equal the base.ToString()
this.CellName = base.ToString();
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged (String propertyName) {
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler) {
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public MainWindow() {
InitializeComponent();
ViewModel = new MainViewModel();
DataGrid Sheet = null;
if (this.FindName("Sheet") is DataGrid)
Sheet = (DataGrid)this.FindName("Sheet");
if (Sheet == null)//Exit
this.Close();
IValueConverter converter = new ModelCellConverter();
Binding bind;
for (int i = 0; i < 26; i++) {
DataGridColumn col = new DataGridTextColumn();
col.Header = (char)('A' + i);
col.IsReadOnly = true;
col.Width = new DataGridLength(60);
col.CanUserSort = false;
//bind = new Binding(new String((char)('A' + i), 1));
bind = new Binding("indexAbleArr[" + i + "].Value");
//bind.Converter = new IdentityConverter();
bind.Mode = BindingMode.OneWay;
((DataGridTextColumn)col).Binding = bind;
Sheet.Columns.Add(col);
}
Sheet.ItemsSource = ViewModel.Rows;
//Current cell display
Label lab = null;
if (this.FindName("CurCell") is Label) {
lab = (Label)this.FindName("CurCell");
bind = new Binding("ActiveCell.CellName");
bind.Source = ViewModel;
bind.NotifyOnSourceUpdated = true;
lab.SetBinding(Label.ContentProperty, bind);
} //Don't bind the label if i cant find it
if (this.FindName("ValueBox") is Label) {
lab = (Label)this.FindName("ValueBox");
bind = new Binding("ActiveCell");
bind.Source = ViewModel;
bind.Converter = converter;
bind.NotifyOnSourceUpdated = true;
lab.SetBinding(Label.ContentProperty, bind);
}
TextBox content = null;
if (this.FindName("Content") is TextBox) {
content = (TextBox)this.FindName("Content");
bind = new Binding("ActiveCell.Contents");
bind.Source = ViewModel;
bind.Mode = BindingMode.TwoWay;
bind.NotifyOnSourceUpdated = true;
content.SetBinding(TextBox.TextProperty, bind);
}
ViewModel.ActiveCell = ViewModel.Rows[0].indexAbleArr[0];
}
我使用XAML地指定佈局,但沒有綁定通過XAML這樣做沒有什麼值得一提的是在我的XAML代碼。行是包含用於綁定目的的模型單元陣列(indexAbleArray)的對象。它還爲綁定預先創建了26個需要的模型單元,不會拋出一百萬個空指針異常。
我正在做類似的事情,但我使用的是GridView,在一個單獨的詳細框架中,對單個值的更新可以在GridView中改變多個值,並顯示出來,但我並不熟悉ViewModel,但我知道我必須將行綁定到一個ObservableCollection才能使它工作,我會連接一個通過轉換器的通道,這樣你就可以驗證這個叫做call並捕獲任何錯誤 – Paparazzi
我跳過綁定到一個ObservableCollection,因爲我可以綁定直接到數組中的值,因爲他們有InotifyPropertyChanged事件。正如我所說的那樣,這種技術對更新的singel單元很有用,但不是潛在的依賴。 – Nathan
但是網格綁定到集合上!你需要一個集合來轉發INotify – Paparazzi