使用MVVM模式中的WPF DataGridComboBoxColumn - 绑定到ViewModel中的属性

11

我正在使用优秀的MVVM Light Toolkit。我的ViewModel公开:

public const string CourtCodesTypeCourtPropertyName = "CourtCodesTypeCourt";
private List<CourtType> _courtCodesTypes = new List<CourtType>();
public List<CourtType> CourtCodesTypeCourt
{
    get
    {
        return _courtCodesTypes;
    }

    set
    {
        if (_courtCodesTypes == value)
        {
            return;
        }

        var oldValue = _courtCodesTypes;
        _courtCodesTypes = value;

        // Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
        RaisePropertyChanged(CourtCodesTypeCourtPropertyName, oldValue, value, true);
    }
}

public const string CourtCodesPropertyName = "CourtCodes";
private List<Court> _courtCodes = null;
public List<Court> CourtCodes
{
    get
    {
        return _courtCodes;
    }

    set
    {
        if (_courtCodes == value)
        {
            return;
        }

        var oldValue = _courtCodes;
        _courtCodes = value;

        // Update bindings and broadcast change using GalaSoft.Utility.Messenging
        RaisePropertyChanged(CourtCodesPropertyName, oldValue, value, true);
    }
}

这个视图有一个数据网格:

<DataGrid
      ItemsSource="{Binding CourtCodes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
      AutoGenerateColumns="False"
      AlternatingRowBackground="{DynamicResource OffsetBrown}"
      AlternationCount="1" Margin="45,0">
   <DataGrid.Columns>
    <DataGridTextColumn Binding="{Binding Abbreviation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
         Header="Abbreviation"
         Width="25*" />
    <DataGridTextColumn Binding="{Binding FullName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
         Header="Court"
         Width="75*" />
    <DataGridComboBoxColumn Header="CourtType" 
         ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CourtCodesTypeCourt} TextBinding="{Binding CourtTypeDescription}""/>
   </DataGrid.Columns>
  </DataGrid>

DataGrid有一个ItemsSource,如您所见,是CourtCodes。我希望CourtType列是包含在CourtCodesTypeCourt中的所有枚举CourtTypes的下拉列表。但我无法似乎将DataGridComboBoxColumn与任何内容相匹配。目前的失败尝试正在寻找使用RelativeSource...那么我错在哪里了?

除了不起作用外,我看到的两个错误是:

System.Windows.Data错误:4:找不到引用'RelativeSource FindAncestor,AncestorType ='System.Windows.Window',AncestorLevel ='1''的绑定源。BindingExpression:Path = DataContext.CourtCodesTypeCourt; DataItem = null; target element is 'DataGridComboBoxColumn' (HashCode = 38771709); target property is' ItemsSource '(type 'IEnumerable')

System.Windows.Data Error:40:BindingExpression路径错误:'CourtCodesTypeCourt'属性在对象'“Court”(HashCode=38141773)'上未找到。BindingExpression:Path = CourtCodesTypeCourt.CourtTypeDescription; DataItem ='Court' (HashCode=38141773); target element is' ComboBox '(Name=''); target property is' Text '(type' String ')

3个回答

28

DataGrid 的列定义不像你期望的那样参与逻辑树。这很荒谬,但据我最后检查,你必须像这样做:

<DataGridComboBoxColumn Header="CourtType" SelectedItemBinding="{Binding Type}">
    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CourtCodesTypeCourt}"/>
            <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.CourtCodesTypeCourt}"/>
        </Style>
    </DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>

你会注意到我还将你的TextBinding更改为SelectedItemBinding。我不确定你是否真的想要一个TextBinding,但如果你只是想让用户在列表中进行选择,那么SelectedItemBinding可能是你想要的。

此外,你的VMs并没有遵循最佳实践。你使用了List<T>而不是ObservableCollection<T>,并且将其公开为List<T>而不是像ICollection<T>这样更简单的东西。


谢谢你的帮助,肯特...这确实让我更接近了。我同意...不得不诉诸这种语法是荒谬的。我正在努力。现在,我已经将CourtType对象填充到DataGridComboBoxColumn中,但在这个语法中,如何控制显示的文本呢?目前它列出了类型名称,而不是它的CourtTypeDescription属性。其次,我感谢您关于最佳实践的反馈...也许我错误地认为MVVM Light Toolkit将mvvminpc片段创建的属性转换为ObservableCollections...我错了吗? - Mike L
忽略ObservableCollections的最佳实践问题...我进行了一些测试并看到了它的价值。仅仅从能够钩入CollectionChanged事件的能力来看,似乎已经足够好了。对于DataGridComboBoxColumn的语法,我可能需要一些提示...再次感谢您的帮助! - Mike L
@Mike:你只需要在你的DataGridComboBoxColumn上设置DisplayMemberPath="CourtTypeDescription"就可以了。 - Kent Boogaart
+1 RelativeSource 的建议让我找到了解决 DataGrid 样式绑定中的另一个问题的正确方法。非常感谢! :) - Dan J
请务必记得将“DataContext”添加到路径中(如此处所示)。我曾经犯过这个错误好几次。 - Simon_Weaver

4

我在这里找到了答案:http://cinch.codeplex.com/discussions/239522

对于DataGridComboBoxColumn,您需要创建一个ItemsSource的StaticRecource,例如:

<CollectionViewSource Source="{Binding Element=theView, Path=DataContext.ViewModelCollection1}" x:Key="ViewModelCollection1" />

并使用以下方式将其绑定到DataGridComboBoxColumn:

ItemsSource="{Binding Source={StaticResource ViewModelCollection1}}"

这是因为DataGridColumns不是可视树的一部分。

如果您想要绑定DataGrid中某个项的集合,您需要通过两个样式设置ItemsSource:

<DataGridComboBoxColumn.ElementStyle>
    <Style TargetType="ComboBox">
        <Setter Property="ItemsSource" Value="{Binding Path=ModelCollection1}" />
    </Style> </DataGridComboBoxColumn.ElementStyle> <DataGridComboBoxColumn.EditingElementStyle>
    <Style TargetType="ComboBox">
        <Setter Property="ItemsSource" Value="{Binding Path=ModelCollection1}" />
    </Style> </DataGridComboBoxColumn.EditingElementStyle>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接