KyloRen
KyloRen

Reputation: 2741

Binding ObservableCollection to DataGrid ComboBox?

I am trying to bind the items of the ComboBox with an ObservableCollection, I have been successfully binding them to a StaticResource,

The XAML, Nursing_Home_Name is the SQL Server Table and this code works fine for me.

<Window.Resources>
    <local:CollectionsLists x:Key="StaticNursingHomeList" />
</Window.Resources>


<DataGridTemplateColumn Width="120" Header="施設名称">
   <DataGridTemplateColumn.CellTemplate>
      <DataTemplate>
         <TextBlock Text="{Binding UpdateSourceTrigger=PropertyChanged,
                           Path=Nursing_Home_Name}" />
      </DataTemplate>
   </DataGridTemplateColumn.CellTemplate>
   <DataGridTemplateColumn.CellEditingTemplate>
       <DataTemplate>
          <ComboBox Text="{Binding Path=Nursing_Home_Name,
                           UpdateSourceTrigger=PropertyChanged}"
                           ItemsSource="{Binding NursingHome, 
                           Source={StaticResource StaticNursingHomeList}}" />
       </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

And code behind,

class CollectionsLists
    {     
        public static List<string> NursingHome { get; set; } 
        var homeNames = Database.GetNursingHomeNames(_nursingHomeSection);
        if (homeNames != null)
        {
           NursingHome = new List<string>();
           foreach (var item in homeNames)
           {
                NursingHome.Add(item);
           }
        }
    }

Now for the problem code,

I am finding it very hard to debug the XAML on what I am doing wrong.

This is the code behind,

public partial class MainWindow : INotifyPropertyChanged
    {        
        public MainWindow()
        { 
            DataContext = this; 
            InitializeComponent();
        }

        private ObservableCollection<string> _nursingHomeNames = new ObservableCollection<string>();

        public ObservableCollection<string> NursingHomeNames
           {
               get { return _nursingHomeNames; }
               set
               {
                   _nursingHomeNames = value;
                   NotifyPropertyChanged();
               }
           }
}

And I cannot show the multitude of ways that I have tried to get the XAML to work, but instead I will post what I thought was the closest to getting it to work,

The XAML, Nursing_Home_Name is the SQL Server Table BTW

<DataGridTemplateColumn Width="120" Header="施設名称">
   <DataGridTemplateColumn.CellTemplate>
      <DataTemplate>
         <TextBlock Text="{Binding UpdateSourceTrigger=PropertyChanged,
                           Path=Nursing_Home_Name}" />
      </DataTemplate>
   </DataGridTemplateColumn.CellTemplate>
   <DataGridTemplateColumn.CellEditingTemplate>
       <DataTemplate>
          <ComboBox Text="{Binding Path=Nursing_Home_Name,
                           UpdateSourceTrigger=PropertyChanged}"
                           ItemsSource="{Binding NursingHomeNames}" />
       </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

What do I need to add to get this to bind correctly?

Upvotes: 0

Views: 1134

Answers (2)

mm8
mm8

Reputation: 169200

What do I need to add to get this to bind correctly?

Since NursingHomeNames is a property of the parent window and the DataContext of the ComboBox is an item in the ItemsSource collection of the DataGrid, you need to specify the window as the source of the binding. Try this:

<DataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate>
        <ComboBox ItemsSource="{Binding Path=NursingHomeNames, RelativeSource={RelativeSource AncestorType=Window}}"
                          SelectedItem="{Binding Path=Nursing_Home_Name}"/>
    </DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>

Upvotes: 1

Emad
Emad

Reputation: 3929

Binding in WPF uses what's called the DataContext of current context. In your case DataContext is of your MainWindow and know this that you can't have two of these in one context for example you can declare another one inside your DataGrid but you can't use the one from MainWindow any more. In short you can't bind to Nursing_Home_Name and NursingHomeNames in the same context.

Ok what's the solution then?

You have to bring one of these properties to the other context. It's simpler to bring your Nursing_Home_Name to your MainWindow like this:

public partial class MainWindow : INotifyPropertyChanged
{        
    public MainWindow()
    { 
        DataContext = this; 
        InitializeComponent();
    }

    private ObservableCollection<string> _nursingHomeNames = new ObservableCollection<string>();

    public ObservableCollection<string> NursingHomeNames
       {
           get { return _nursingHomeNames; }
           set { _nursingHomeNames = value; }
       }

    public string Nursing_Home_Name //Unconventional name. But I kept your naming
    {
        get { return GetNursingHomeNameFromDB(); }
        set 
        {
            SaveNursingHomeName(value); 
            NotifyPropertyChanged("Nursing_Home_Name");
        }
    }
}

This will work if you implement GetNursingHomeNameFromDB and SaveNursingHomeName.

One final tip: ObservableCollection<T> doesn't require NotifyPropertyChanged() it's built in.

Upvotes: 2

Related Questions