ComboBox in my WPF DataGrid won't display any

2019-08-23 03:49发布

I have a WPF user control that contains a DataGrid. This DG contains several columns including a ComboBox for states. The list of states is populated and stored as a property in my ViewModel.

I am trying to bind the StateList Property to the ItemsSource of my Combobox but when I run the form and try to edit the DG, the combobox does not contain any values, the combobox is empty.

Here is the XAML for the usercontrol.

<UserControl x:Class="myproject.View.ucContactView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" d:DesignHeight="475" d:DesignWidth="977">
<UserControl.Resources>
    <ResourceDictionary Source="/Templates/MyResourceDictionary.xaml"/>
</UserControl.Resources>
<Grid DataContext="{Binding ViewModel}">
    <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding AddressCollectionViewSource.View}">
        <DataGridTemplateColumn Header="State" Width="160">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding StateDescription}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <ComboBox Name="cboState"
                                  SelectedValuePath="StateKey"
                                  ItemTemplate="{StaticResource dtStateTemplate}"
                                  ItemsSource="{Binding StateList}" 
                                  SelectedItem="{Binding StateKey, Mode=TwoWay}"
                                  Width="100" />
                    </StackPanel>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
    </DataGrid>
</Grid>
</UserControl>

The odd thing is that if I create another combobox on this usercontrol with the exact same combobox, this combobox works as expected.

<!-- this works as long as it's not in the DG -->
<StackPanel Height="126" HorizontalAlignment="Left" Margin="766,275,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="200" >
    <ComboBox Name="cboState2"
          SelectedValuePath="StateKey"
          ItemTemplate="{StaticResource dtStateTemplate}"
          ItemsSource="{Binding StateList}" 
          SelectedItem="{Binding StateKey, Mode=TwoWay}"
          Width="100" />
</StackPanel>

Why won't the combobox in the DG display the values from the StateList property? Any why does the separate combobox work properly?

2条回答
乱世女痞
2楼-- · 2019-08-23 04:15

if your viewmodel is a property at the window you can do this

ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ViewModel.StateList, Mode=OneWay}"


<Window x:Class="WpfStackOverflowSpielWiese.Window2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window2"
        Height="300"
        Width="300"
        x:Name="window">

  <Grid DataContext="{Binding ElementName=window, Path=ViewModel}">

    <DataGrid x:Name="grid"
              AutoGenerateColumns="False"
              ItemsSource="{Binding AddressCollectionViewSource, Mode=OneWay}">

      <DataGrid.Columns>
        <DataGridTemplateColumn Header="State"
                                Width="160">

          <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              <TextBlock Text="{Binding StateKey}" />
            </DataTemplate>
          </DataGridTemplateColumn.CellTemplate>

          <DataGridTemplateColumn.CellEditingTemplate>
            <DataTemplate>
              <StackPanel Orientation="Horizontal">
                <ComboBox Name="cboState"
                          SelectedValuePath="StateKey"
                          ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ViewModel.StateList, Mode=OneWay}"
                          SelectedItem="{Binding StateKey, Mode=TwoWay}"
                          Width="100" />
              </StackPanel>
            </DataTemplate>
          </DataGridTemplateColumn.CellEditingTemplate>

        </DataGridTemplateColumn>
      </DataGrid.Columns>

    </DataGrid>
  </Grid>
</Window>


using System.Collections.ObjectModel;
using System.Windows;

namespace WpfStackOverflowSpielWiese
{
  /// <summary>
  /// Interaction logic for Window2.xaml
  /// </summary>
  public partial class Window2 : Window
  {
    public static readonly DependencyProperty ViewModelProperty =
      DependencyProperty.Register("ViewModel", typeof(ViewModelClass), typeof(Window2), new PropertyMetadata(default(ViewModelClass)));

    public ViewModelClass ViewModel {
      get { return (ViewModelClass)this.GetValue(ViewModelProperty); }
      set { this.SetValue(ViewModelProperty, value); }
    }

    public Window2() {
      this.InitializeComponent();
      this.grid.Items.Clear();
      this.ViewModel = new ViewModelClass();
    }
  }

  public class StateClass : DependencyObject
  {
    public static readonly DependencyProperty StateKeyProperty =
      DependencyProperty.Register("StateKey", typeof(string), typeof(ViewModelClass), new PropertyMetadata(default(string)));

    public string StateKey {
      get { return (string)this.GetValue(StateKeyProperty); }
      set { this.SetValue(StateKeyProperty, value); }
    }

    public static readonly DependencyProperty StateProperty =
      DependencyProperty.Register("State", typeof(string), typeof(StateClass), new PropertyMetadata(default(string)));

    public string State {
      get { return (string)this.GetValue(StateProperty); }
      set { this.SetValue(StateProperty, value); }
    }
  }

  public class ViewModelClass : DependencyObject
  {
    public static readonly DependencyProperty StateListProperty =
      DependencyProperty.Register("StateList", typeof(ObservableCollection<string>), typeof(ViewModelClass), new PropertyMetadata(default(ObservableCollection<string>)));

    public static readonly DependencyProperty AddressCollectionViewSourceProperty =
      DependencyProperty.Register("AddressCollectionViewSource", typeof(ObservableCollection<StateClass>), typeof(ViewModelClass), new PropertyMetadata(default(ObservableCollection<StateClass>)));

    public ObservableCollection<StateClass> AddressCollectionViewSource {
      get { return (ObservableCollection<StateClass>)this.GetValue(AddressCollectionViewSourceProperty); }
      set { this.SetValue(AddressCollectionViewSourceProperty, value); }
    }

    public ObservableCollection<string> StateList {
      get { return (ObservableCollection<string>)this.GetValue(StateListProperty); }
      set { this.SetValue(StateListProperty, value); }
    }

    public ViewModelClass() {
      this.StateList = new ObservableCollection<string>(new[] {"one", "two"});
      this.AddressCollectionViewSource = new ObservableCollection<StateClass>(new[] {new StateClass {State = "state", StateKey = "one"}});
    }
  }
}
查看更多
闹够了就滚
3楼-- · 2019-08-23 04:20

It's not working because your ComboBox is looking for StateList as a property of the DataContext of the DataGrid. That is, it's trying to bind to ViewModel.AddressCollectionViewSource.View.StateList when it needs to be binding to ViewModel.StateList. Check your output window while debugging and I bet you'll see a binding error to the effect of Could not find property StateList on object AddressCollectionViewSource (or maybe ICollection).

Try this instead:

<ComboBox Name="cboState2" 
      SelectedValuePath="StateKey" 
      ItemTemplate="{StaticResource dtStateTemplate}" 
      ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,
            AncestorType={x:Type DataGrid}}, Path=DataContext.StateList}"  
      SelectedItem="{Binding StateKey, Mode=TwoWay}" 
      Width="100" /> 
查看更多
登录 后发表回答