我是WPF开发的新手。我刚刚创建了一个示例来重新创建场景。我根据父行中的复选框切换rowdetailsview中datagrid的IsReadonly属性。
除了特定情况外,一切正常。
如何重现问题。
保持最初创建的父行检查。 取消选中父行。 转到子行id属性。 清除id字段中的所有内容并从该单元格中删除选项卡,您将看到空引用异常。
我不知道如何解决这个问题。任何见解都会非常有用。
代码背后的代码:
namespace WpfApplication7
{/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public PerColl People { get; private set; }
public MainWindow()
{
InitializeComponent();
this.People = new PerColl();
this.DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
public class Person
: INotifyPropertyChanged, IEditableObject
{
public string Name { get; set; }
public double Salary
{
get { return _salary; }
set
{
if (this._salary == value)
return;
this._salary = value;
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("Salary"));
}
}
public bool IsLocked
{
get { return _isLocked; }
set
{
if (this._isLocked == value)
return;
this._isLocked = value;
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("IsLocked"));
}
}
public ObservableCollection<Kid> Kids { get; set; }
public Person(string name, double salary)
{
this.Name = name;
this.Salary = salary;
}
public Person()
{
this.Salary = 10000;
this.Name = "abc";
this.IsLocked = true;
this.Kids = new ObservableCollection<Kid>();
this.Kids.Add(new Kid(1));
this.Kids.Add(new Kid(2));
}
private bool _isLocked;
private double _salary;
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public void BeginEdit()
{
if (isEdit) return;
isEdit = true;
this.backup = this.MemberwiseClone() as Person;
}
public void CancelEdit()
{
if (!this.isEdit)
return;
isEdit = false;
this.Name = this.backup.Name;
this.Salary = this.backup.Salary;
}
public void EndEdit()
{
if (this.isEdit == false)
return;
this.isEdit = false;
this.backup = null;
}
private bool isEdit;
private Person backup;
}
public class PerColl : ObservableCollection<Person> { }
public class Kid : IEditableObject,INotifyPropertyChanged
{
public int Id
{
get { return _id; }
set
{
this._id = value;
if (PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("Id"));
}
}
public string Name
{
get { return _name; }
set
{
this._name = value;
if (PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
public Person Parent { get; set; }
public Kid()
{
this.Id = 12345;
this.Name = "kidname";
}
public Kid(int id, string name = "kidname")
{
this.Id = 12345;
this.Name = name;
}
#region IEditableObject Members
public void BeginEdit()
{
if (isEdit) return;
isEdit = true;
this.backup = this.MemberwiseClone() as Kid;
}
public void CancelEdit()
{
if (!this.isEdit)
return;
isEdit = false;
this.Id = backup.Id;
}
public void EndEdit()
{
if (this.isEdit == false)
return;
this.isEdit = false;
this.backup = null;
}
#endregion
private int _id;
private string _name;
private bool isEdit;
private Kid backup;
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
}
Xaml代码:
<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<DockPanel LastChildFill="True" Margin="-1,5,1,-5">
<Button Content="Add" Height="30" Click="Button_Click" DockPanel.Dock="Top"/>
<DataGrid ItemsSource="{Binding Path=People}"
AutoGenerateColumns="False"
SelectionUnit="CellOrRowHeader"
RowDetailsVisibilityMode="Visible">
<DataGrid.Columns>
<DataGridTextColumn Header="Salary" Binding="{Binding Path=Salary,StringFormat='{}{0:#,0}'}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
<DataGridCheckBoxColumn Header="IsLocked" Binding="{Binding Path=IsLocked,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid
ItemsSource="{Binding Path=Kids}"
AutoGenerateColumns="False"
IsReadOnly="{Binding Path=IsLocked}"
SelectionUnit="CellOrRowHeader">
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Path=Id,StringFormat='{}{0:#,0}'}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</DockPanel>
答案 0 :(得分:0)
您可以将ID的类型从 int 更改为字符串
如果Id列为Unique,则必须将其设为 ReadOnly
或者你可以通过IvalueConverter处理它
关注此
创建一个类并实现IValueConverter
public class IntConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null || value.ToString()=="")
return 0;
return value;
}
}
然后将Coverter作为资源添加到您的Window
xmlns:local="clr-namespace:WpfApplication1"
和
<Window.Resources>
<local:IntConverter x:Key="converter" />
</Window.Resources>
最后将转换器添加到 ID 列
<DataGridTextColumn Header="Id" Binding="{Binding Path=Id,StringFormat='{}{0:#,0}',Converter={StaticResource converter}}" />
答案 1 :(得分:0)
尝试在Id列上设置TargetNullValue并使Kid.Id成为可以为空的int,然后你应该解决问题。
有关TargetNUllValue属性的信息,请参阅:http://msdn.microsoft.com/en-us/library/system.windows.data.bindingbase.targetnullvalue.aspx
代码背后:
public class Kid : IEditableObject, INotifyPropertyChanged
{
public int? Id
{
get { return _id; }
set
{
this._id = value;
if (PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("Id"));
}
}
public string Name
{
get { return _name; }
set
{
this._name = value;
if (PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
public Person Parent { get; set; }
public Kid()
{
this.Id = 12345;
this.Name = "kidname";
}
public Kid(int? id, string name = "kidname")
{
this.Id = id;
this.Name = name;
}
#region IEditableObject Members
public void BeginEdit()
{
if (isEdit) return;
isEdit = true;
this.backup = this.MemberwiseClone() as Kid;
}
public void CancelEdit()
{
if (!this.isEdit)
return;
isEdit = false;
this.Id = backup.Id;
}
public void EndEdit()
{
if (this.isEdit == false)
return;
this.isEdit = false;
this.backup = null;
}
#endregion
private int? _id;
private string _name;
private bool isEdit;
private Kid backup;
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
WPF :(确保您已添加系统:引用
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<DockPanel LastChildFill="True" Margin="-1,5,1,-5">
<Button Content="Add" Height="30" Click="Button_Click" DockPanel.Dock="Top"/>
<DataGrid ItemsSource="{Binding Path=People}"
AutoGenerateColumns="False"
SelectionUnit="CellOrRowHeader"
RowDetailsVisibilityMode="Visible">
<DataGrid.Columns>
<DataGridTextColumn Header="Salary" Binding="{Binding Path=Salary,StringFormat='{}{0:#,0}'}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
<DataGridCheckBoxColumn Header="IsLocked" Binding="{Binding Path=IsLocked,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid
ItemsSource="{Binding Path=Kids}"
AutoGenerateColumns="False"
IsReadOnly="{Binding Path=IsLocked}"
SelectionUnit="CellOrRowHeader">
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Path=Id,StringFormat='{}{0:#,0}', TargetNullValue={x:Static system:String.Empty}}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</DockPanel>
</Window>