【问题标题】:WPF ComboBox in Datagrid throws error if Binding is NULL如果 Binding 为 NULL,Datagrid 中的 WPF ComboBox 会引发错误
【发布时间】:2015-03-07 21:06:20
【问题描述】:

我有一个要编辑的 DataGrid。一列是一个组合框

<DataGrid ItemsSource="{Binding Persons, Mode=TwoWay}"
          SelectedItem="{Binding SelectedPerson, Mode=TwoWay}" >
     <DataGrid.Columns>
         <DataGridTemplateColumn Header="Company" >
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.Companies}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Company.Name}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

问题是如果公司是null 那么我得到错误

双向绑定需要 Path 或 XPath

我怎样才能解决这个问题以允许将 Company 设置为 null?

【问题讨论】:

  • 你刷新了itermsource吗?你能分享一下背后的代码吗
  • 绑定最初是否成功(即只是更新不正确)?
  • "Path=DataContext.Companies" Companies 属性是否实现 INotifyPropertyChanged?
  • 这可能有几个原因,如果你没有实现 INotifyPropertyChanged,如果你的 updatesourcetrigger 不正确等等。后面的代码会很有帮助。
  • 我认为您只需要在模型视图构造函数中初始化“公司”(例如:Companies = new List())。

标签: c# wpf mvvm data-binding datagrid


【解决方案1】:

Text="{Binding Company.Name}"always 要求 Company 是一个有效对象,因为系统希望最终访问 Name 属性。我仍然希望您可以创建一个虚拟公司对象并将名称设置为空字符串。否则,转换器会有所帮助:

<DataGrid ItemsSource="{Binding Persons, Mode=TwoWay}"
      SelectedItem="{Binding SelectedPerson, Mode=TwoWay}" >
    <DataGrid.Resources>
        <local:MyConverter x:Key="MyConverter"/>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Company" >
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.Companies}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Company, Converter={StaticResource MyConverter}}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>


public class MyConverter : IValueConverter
{
    public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
        {
            return string.Empty;
        }

        Type myType = value.GetType ();
        PropertyInfo pinfo = myType.GetProperty ("Name");

        if (pinfo == null)
        {
            return string.Empty;
        }

        return (string)pinfo.GetValue(value);
    }

    public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

转换器使用反射来访问Name 属性。如果转换器可以访问Company 的类型(并且逻辑允许),您当然可以直接使用。

【讨论】:

  • 谢谢。我现在没有收到任何错误。唯一的问题是当列进入编辑模式并出现组合框时 - SelectedItem 为 NULL。但它应该是只读模式下 TextBox 中的值。
  • 我看不到解决 SelectedItem 为 Null 的方法。原因很简单。 Componies 列表中的条目与所选项目之间存在 1:1 的关系。如果一个条目是 Null 并且您选择它,SelectedItem 肯定是 Null。当然,不可能编辑一个对象的属性(在本例中为名称),因为它是 Null。我再次鼓励您添加真实的、实例化的虚拟对象而不是 Null。向Company 添加一个附加属性可能会有所帮助,以指示它是虚拟公司还是真实公司。
【解决方案2】:

这个问题已经有了正确的答案,所以这只是一个快速跟进。 让我们假设一个演示 ViewModel:

public MyViewModel()
{
    CompanyType companyA = new CompanyType();
    companyA.Name = "Comp. A";
    CompanyType companyB = new CompanyType();
    companyB.Name = "Comp. B";
    Companies.Add(companyA);
    Companies.Add(companyB);
    PersonType person1 = new PersonType();
    person1.Id = 1;
    person1.Company = null;
    PersonType person2 = new PersonType();
    person2.Id = 2;
    person2.Company = companyB;
    persons.Add(person1);
    persons.Add(person2);
}

现在,在 ComboBox 中不起作用的是,在从 ComboBox 中选择了不同 Company 的新值后,它不会更改 Person's Company 的值:在演示中,假设我们要同时分配 person1 和 2从 UI 到 companyA。

此外,如果我们不将 ComboBox 的 SelectedItem 绑定到 PersonType 的 Company 属性,在 person2 的 ComboBox 中选择 CompanyB。

在这里您可以找到 Combobox 的 Xaml 的修复程序

                <DataTemplate>
                    <ComboBox
                        DisplayMemberPath="Name"
                        SelectedValuePath="Name"
                        SelectedItem="{Binding Company}"
                        ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=DataContext.Companies}"/>
                </DataTemplate>

我的演示类

public class PersonType // don't need to notify below
{
    public int Id { get; set; }
    public CompanyType Company { get; set; }
}
public class CompanyType
{
    public string Name { get; set; }
}

请注意另外,由于绑定了 Combobox SelectedItem,person2 的 ComboBox 项 CompanyB 在开始时selected,现在可以更改一个例如,公司到公司 A。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-25
    • 2012-07-31
    • 2011-08-23
    • 1970-01-01
    • 2017-05-23
    • 2016-05-02
    • 2020-02-01
    • 2013-06-30
    相关资源
    最近更新 更多