簡體   English   中英

如何在保持雙向綁定 MVVM 的同時將 Linq 結果綁定到 WPF DataGrid

[英]How to bind a Linq result to a WPF DataGrid while keeping two way binding MVVM

所以我非常了解我的問題,我只是在為它開發解決方案時遇到問題。 假設我有一個帶有數據網格的 MVVM WPF 應用程序。 ItemSource 綁定到集合 ObservableCollection。 這是通過轉換器饋送的,因為數據模型相當復雜,但模型復雜性與問題無關。 然后我需要對我的可觀察集合使用 Linq 查詢,因為我希望它只顯示該集合中的某些項目。

如果我直接從我的轉換器返回 Linq 查詢,我會收到錯誤“ 'EditItem' is not allowed for this view. ” 我意識到發生該錯誤是因為 Linq 查詢返回一個 IEnumerable 集合,而 DataGrid TwoWay 數據不支持該集合捆綁。

但是,如果我將其作為新的 ObservableCollection 返回,則會收到錯誤“雙向綁定需要 Path 或 XPath”。這是有道理的,因為新集合不是具有訪問器和修改器的屬性,而且,我們丟失了數據綁定以這種方式到原始來源。

所以這里的問題是我如何只從轉換器返回我需要的項目,以這種方式將我的數據綁定到原始源並允許雙向綁定?

我不確定以下是否有必要,但關於此應用程序的背景可能值得一提。 此應用程序在選項卡控件中動態生成了選項卡,每個選項卡項都包含這些 DataGrid 之一。 這些數據網格填充有相同的對象集合,只是每個對象都有不同的過濾器,具體取決於它包含在哪個選項卡中(這一切都與模型相關聯)。 轉換器在那里很重要,因為向任何數據網格添加項目都需要一些額外的編碼。

下面是一些代碼來演示這個問題。

XAML 數據網格:

<DataGrid IsReadOnly="False">
    <DataGrid.ItemsSource>
        <MultiBinding Converter="{StaticResource MyObjectCollectionDataGridConverter}" UpdateSourceTrigger="PropertyChanged">
            <Binding Path="StateManager.MyObjectCollection" Mode="TwoWay"/>
            <Binding Mode="OneWay"/>
        </MultiBinding>
    </DataGrid.ItemsSource>
</DataGrid>

C# 轉換器

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
    string header = ((MyObjectType)values[1]).Name;

    // Returning as a Linq query:
    // return ((ObservableCollection<MyObject>)values[0]).Where(c => c.Type.Name == header);

    // Returning as a new Observable Collection
    return new ObservableCollection<MyObject>(((ObservableCollection<MyObject>)values[0]).Where(c => c.Type.Name == header));
}

感謝您的任何幫助!!!

編輯

好的,所以我確實發現在使用 Linq 查詢方法時,通過調用 ToList() 方法,我的數據綁定確實適用於現有項目(這是有道理的,因為它只是引用對象的舊實例)。 但是,當通過數據網格添加新項目時,應用程序會因錯誤“雙向綁定需要 Path 或 XPath ”而中斷 (這也是有道理的,因為它沒有引用創建的新列表,而不是舊的可觀察集合)。 如何使它仍然可以通過數據網格添加項目以在新列表上引用舊的可觀察集合?

由於 View 決定了 VM 應該是什么樣子,因此您的 MyObject 也應遵循此規則。

您想擴展 MyObject 類以包含項目是否可見的標志。

這是您的 RowViewModel 的外觀:

public class MyObject : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged();
        }
    }

    private bool _isEnabled;
    public bool IsEnabled
    {
        get { return _isEnabled; }
        set
        {
            _isEnabled = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged([CallerMemberName] string propName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    }
}

以下是您在轉換器中處理它的方法:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
     string header = ((MyObject)values[1]).Name;
     foreach (var item in (ObservableCollection<MyObject>)values[0])
         item.IsEnabled = item.Name == header;

     return values[0];
}

當然,您希望在DataTemplate xaml 中公開啟用的標志:

<DataGrid IsReadOnly="False" AutoGenerateColumns="False">
   <DataGrid.ItemsSource>
    <MultiBinding Converter="{StaticResource MyObjectCollectionDataGridConverter}" UpdateSourceTrigger="PropertyChanged">
        <Binding Path="StateManager.MyObjectCollection" Mode="TwoWay"/>
        <Binding Mode="OneWay"/>
    </MultiBinding>
   </DataGrid.ItemsSource>
   <DataGrid.Columns>
          <DataGridTemplateColumn>
              <DataGridTemplateColumn.CellTemplate>
                  <DataTemplate>
                      <TextBox Text="Hello" IsEnabled="{Binding IsEnabled}"/>
                  </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
          </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM