2011-04-01 179 views
26

我已經看過variousquestions的答案,但還沒有設法將答案中的內容映射到我試圖解決的問題上。我已經將它縮減爲下面的代碼(代表我嘗試實現的結果),並且基本上希望能夠在行未被編輯時呈現Person.TitleId作爲其對應的Title.TitleText,並且具有下降正確綁定,以便它在下拉列表中顯示TitleText,並在關聯的TitleId記錄更改後將其寫回Person記錄。用MVVM綁定WPF DataGridComboBoxColumn

總之,我爲了達到這個目的在<DataGridComboBoxColumn>中放什麼?

App.xaml.cs

protected override void OnStartup(StartupEventArgs e) 
{ 
    base.OnStartup(e); 

    var viewModel = new ViewModels.MainWindowViewModel(); 
    var mainWindow = new MainWindow(); 
    mainWindow.DataContext = viewModel; 
    mainWindow.ShowDialog(); 
} 

MainWindow.xaml

<Grid> 
    <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=Contacts}"> 
     <DataGrid.Columns> 
      <DataGridComboBoxColumn Header="Title" SelectedItemBinding="{Binding Person}"> 
       <DataGridComboBoxColumn.ElementStyle> 
        <Style TargetType="ComboBox"> 
         <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/> 
         <Setter Property="IsReadOnly" Value="True"/> 
        </Style> 
       </DataGridComboBoxColumn.ElementStyle> 
       <DataGridComboBoxColumn.EditingElementStyle> 
        <Style TargetType="ComboBox"> 
         <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/> 
         <Setter Property="DisplayMemberPath" Value="TitleText" /> 
        </Style> 
       </DataGridComboBoxColumn.EditingElementStyle> 
      </DataGridComboBoxColumn> 
     </DataGrid.Columns> 
    </DataGrid> 
</Grid> 

Person.cs

public class Person 
{ 
    public int TitleId { get; set; } 
    public string LastName { get; set; } 
    public string FirstName { get; set; } 
} 

Title.cs

public struct Title 
{ 
    public Title(int titleId, string titleText) 
     : this() 
    { 
     TitleId = titleId; 
     TitleText = titleText; 
    } 

    public string TitleText { get; private set; } 
    public int TitleId { get; private set; } 

    public static List<Title> GetAvailableTitles() 
    { 
     var titles = new List<Title>(); 

     titles.Add(new Title(1, "Mr")); 
     titles.Add(new Title(2, "Miss")); 
     titles.Add(new Title(3, "Mrs")); 

     return titles; 
    } 
} 

MainWindowViewModel.cs

public class MainWindowViewModel : ViewModelBase 
{ 
    private ObservableCollection<Person> contacts; 
    private List<Title> titles; 

    public MainWindowViewModel() 
    { 
     titles = Title.GetAvailableTitles(); 

     Contacts = new ObservableCollection<Person>(); 
     Contacts.Add(new Person() { FirstName = "Jane", LastName = "Smith", TitleId = 2 }); 
    } 

    public List<Title> Titles 
    { 
     get { return titles; } 
    } 

    public ObservableCollection<Person> Contacts 
    { 
     get { return contacts; } 
     set 
     { 
      if (contacts != value) 
      { 
       contacts = value; 
       this.OnPropertyChanged("Contacts"); 
      } 
     } 
    } 
} 

ViewModelBase.cs

public class ViewModelBase : INotifyPropertyChanged 
{ 
    protected void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 
+0

如果你能概述那個「計劃」的哪些部分不起作用/哪些實際上做了,它將會有所幫助。例如你能找到ComboBox的ItemsSource列表嗎? – 2011-04-01 19:32:49

+0

另外:從看起來你如何使用'Title'這個類似乎是多餘的,並且最好由'Dictionary '替代。 – 2011-04-01 19:38:51

+0

@ H.B。 - 如代碼所示,網格不顯示初始值的文本表示(即Person.TitleId的相應TitleText),下拉列表中正確填充{Mr,Mrs,Miss}並選擇一個項目下拉式結果在TestMVVM.Models中。標題顯示在網格中(TestMVVM.Models是解決方案中的名稱空間,爲簡潔起見,我將其刪除)。 – Rob 2011-04-01 19:39:26

回答

35

這裏是一個工作的代碼。這裏的關鍵是使用SelectedValueBinding而不是SelecteItemBinding

<DataGridComboBoxColumn Header="Title" 
         SelectedValueBinding="{Binding TitleId}" 
         SelectedValuePath="TitleId" 
         DisplayMemberPath="TitleText" 
         > 
    <DataGridComboBoxColumn.ElementStyle> 
     <Style TargetType="ComboBox"> 
      <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/> 
     </Style> 
    </DataGridComboBoxColumn.ElementStyle> 
    <DataGridComboBoxColumn.EditingElementStyle> 
     <Style TargetType="ComboBox"> 
      <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/> 
     </Style> 
    </DataGridComboBoxColumn.EditingElementStyle> 
</DataGridComboBoxColumn> 
+0

令人難以置信的是,我只是寫了幾乎完全相同的東西,好吧,這一輪去找你。 – 2011-04-01 20:20:42

+0

這在我的簡化情況下完美運行,我將花費一些時間將其整合到我的實際代碼中,以查看它是否在那裏工作(我確信它會!)。任何你可以解釋的機會*它是如何/爲什麼會起作用的? :) – Rob 2011-04-01 20:36:32

+2

'SelectedValuePath'設置選定對象中代表組合框選定項目的成員的路徑,另一方面'DisplayMemberPath'設置應該顯示的類內成員的路徑。 「SelectedValueBinding」會將選定的值綁定到綁定中指定的屬性。這有點令人困惑,但如果你使用它幾次,這是有道理的。 E:http://stackoverflow.com/questions/3797034/confused-with-wpf-combobox-displaymemberpath-selectedvalue-and-selectedvaluepath – 2011-04-01 20:48:59

2

@ SnowBear的回答對我很好。但我想澄清綁定的細節。

在@ Rob的例子中,Title和Person類都使用TitleID。 因此,在@ SnowBear的回答,在結合:

SelectedValueBinding="{Binding TitleId}" 

它不是立即明顯,我哪個階級和財產的束縛。

因爲SelectedValueBinding屬性出現在DataGridComboBoxColumn上,所以它綁定到包含DataGrid的ItemsSource。在這種情況下,Person對象的Contacts集合。

就我而言,DataGrid的DataSource集合被賦予了一個與ComboBox的ItemSource集合的ValuePath命名不同的屬性。所以我的SelectedValueBinding的值被綁定到一個不同於ComboBox的SelectedValuePath中指定的屬性的屬性。