简体   繁体   English

如果Binding为NULL,则Datagrid中的WPF ComboBox会引发错误

[英]WPF ComboBox in Datagrid throws error if Binding is NULL

I have a DataGrid I want to edit. 我有一个要编辑的DataGrid。 One column is a Combobox 一列是组合框

<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>

The problem is if the Company is null then I get the error 问题是,如果公司为null那么我会收到错误消息

Two-way binding requires Path or XPath 双向绑定需要Path或XPath

How can I get around that to allow the Company be set to null? 我如何解决这个问题,以允许将Company设置为null?

Text="{Binding Company.Name}" always requires Company to be a valid object because the system wants to finally access the Name property. Text="{Binding Company.Name}"始终要求Company为有效对象,因为系统最终希望访问Name属性。 I still have some hope you can create a dummy Company object and set the Name to an empty string. 我仍然希望您可以创建一个虚拟Company对象并将Name设置为空字符串。 Otherwise a converter helps: 否则,转换器将帮助:

<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;
    }
}

The converter uses reflexion to access the Name property. 转换器使用反射来访问Name属性。 If the type of Company is accessible for the converter (and the logic allows it) you can of course use is directly. 如果转换器可以访问Company类型(并且逻辑允许),那么您当然可以直接使用。

The question already has a correct answer, so this is just a quick follow up. 该问题已经有了正确的答案,因此这只是快速跟进。 Let's assume a demo ViewModel: 让我们假设一个演示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);
}

Now, what is not working in the ComboBox is that it is not changing the value of a Person's Company after a new value of a different Company is selected from the ComboBox: in the demo let's say we want assign both persons1 and 2 to companyA from the UI. 现在,在ComboBox中不起作用的是,在从ComboBox中选择了另一个公司的新值之后,它并没有在更改Person's Company的值:在演示中,我们想将person1和2都分配给来自用户界面。

Furthermore CompanyB is not selected in the ComboBox of person2, if we don't bind the SelectedItem of the ComboBox to the Company property of the PersonType. 此外,如果我们不将ComboBox的SelectedItem绑定到PersonType的Company属性, 则不在person2的ComboBox中选择CompanyB。

Here you find the fix to the Xaml of the Combobox 在这里,您可以找到针对组合框Xaml的修复程序

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

The classes of my demo 我的演示课程

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; }
}

Please notice also that, due to the binding of Combobox SelectedItem , person2 has its ComboBox item CompanyB selected in the beginning and now it is possible to change one's Company to CompanyA, for example. 请注意 ,由于Combobox SelectedItem的绑定,person2的开头选择了ComboBox项目CompanyB,现在可以将其Company更改为CompanyA。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM