2011-10-03 7 views
0

그래서 데이터 그리드에서 값을 업데이트 할 수있는 문제가 생겼습니다. 텍스트 상자에서 DataGrid가 선택된 셀의 값을 편집하면 UI 업데이트가 즉시 발생합니다. 함정은 내가이 세포의 가치에 의존하는 임의의 세포를 갱신 할 수 없다는 것이다. 셀/열에 바인딩 된 데이터가 변경되지만 DataGrid는 Dependent 셀 값을 업데이트하지 않습니다. 많은 셀이 있으므로 DataGrid.Item.Refresh()를 호출하는 것은 매우 비용이 많이 듭니다. InotifyProperty 변경된 이벤트를 발생시키는 메서드를 만들려고했지만 아직 그리드에서 업데이트가 발생하지 않습니다. 나는 GUI를 업데이트하도록 강제하는 방법을 잃어 버렸다.DataGrid에서만 선택된 셀을 업데이트합니다.

모델 셀의 코드는 다음과 같습니다. biding 코드는 그 아래에 있습니다.

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)을 포함하는 Object입니다. 또한 바인딩에 필요한 널 (null) 포인터 예외가 발생하지 않도록 26 개의 modelcell을 미리 작성합니다.

+0

비슷한 일을하고 있지만 GridView를 사용하고 있습니다. 하나의 값을 업데이트하면 GridView에서 둘 이상의 값이 변경되어 나타날 수 있습니다. ViewModel에 익숙하지 않지만 나는 그것이 작동하도록 ObservableCollection에 행을 바인드해야한다는 것을 알고 있습니다. 나는 호출을 호출하고 오류를 잡을 수 있도록 변환기 통과를 연결합니다. – Paparazzi

+0

바인딩 할 수있는대로 ObservableCollection에 대한 바인딩을 건너 뜁니다. 그들은 InotifyPropertyChanged 이벤트를 가지고 있기 때문에 배열의 값에 직접적으로 접근 할 수 있습니다.이 기술은 singel 셀은 업데이트되지만 잠재적 인 종속은 아닙니다. – Nathan

+0

하지만 Grid는 컬렉션에 바인딩됩니다! Inotify – Paparazzi

답변

0

DataGridTextColumns의 바인딩 경로에있는 인덱스 기반 열의 부분이 indexAbleArr[" + i + "]이라고 생각합니다. 그들은 속성 변경 알림에 참여하지 않습니다.

BalamBalam이 해당 배열을 ObservableCollection으로 제안했거나 어레이의 셀 int가 Value 일 때 속성 "indexAbleArr"에 대한 행 수준에서 속성 변경 알림을 제기해야합니다.

나에게 모두 실제로 불완전한 디자인입니다. :

+0

나는 모든 종류의 IndexbleArr에 대해 Row 객체 withing 이벤트를 시도했다. [i ] 요법. 나의 혼란은 포커스가있을 때 셀이 업데이트되고 포커스가 없을 때 셀이 업데이트되는 이유입니다. 데이터 그리드가 선택한 셀의 이벤트 만 수신하는 것처럼 – Nathan

관련 문제