我有一些带有一些列的ListView。第一列是复选框类型。另外,我在ListView标题行中放置了一个复选框,用于一次选择/取消选择所有ListView项目。
这是视图(xaml):
<Grid>
<Style x:Key="alternatingStyle" TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="LightBlue" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="LightGray" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<ListView Margin="10" Name="lvUsers" AlternationCount="2" ItemContainerStyle="{StaticResource alternatingStyle}" ItemsSource="{Binding Path=Items}" SelectionMode="Extended">
<ListView.View>
<GridView>
<!-- Checkbox header -->
<GridViewColumn>
<GridViewColumn.Header>
<CheckBox x:Name="CheckAll" Command="{Binding CheckAllCommand}"
CommandParameter="{Binding IsChecked, ElementName=CheckAll}" />
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" />
<GridViewColumn Header="Mail" Width="150" DisplayMemberBinding="{Binding Mail}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
有时(并非总是)当我选中/取消选中listview标题中的复选框以选择/取消选择列表视图中的所有项目时,我得到类型的例外:
Object reference not set to an instance of an object.
我发现传递给icommand“CheckAllCommand”的boolean参数为null所以当我尝试转换为boolean以便它崩溃时,请参阅后面的视图模型代码:
Code-Behind(xaml.cs):
public partial class MainWindow: ViewBaseControl
{
public MainWindow(ViewModelSession vm):base(vm)
{
// DataContext = new myViewModel(); <-- Data context is not initialized here, it is done automatically in the ViewBaseControl class
InitializeComponent();
}
}
ViewBaseControl类:
public class ViewBaseControl : UserControl
{
[Obsolete("To use below constructor", true)]
public ViewBaseControl()
{
}
public ViewBaseControl(ViewModelSession vm)
{
DataContext = vm;
Focusable = true;
Loaded += (sender, e) =>
MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
public ViewModelSession VM
{
get { return DataContext as ViewModelSession; }
}
}
查看模型:
public class myViewModel : ViewModelSession, INotifyPropertyChanged
{
private DataModel _data = null;
private ObservableCollection<DataModel> items = null;
public myViewModel()
{
this.Load();
}
public void Load()
{
items = new ObservableCollection<DataModel>();
items.Add(new DataModel() { IsSelected = false, Name = "John Doe", Age = 42, Mail = "john@doe-family.com" });
items.Add(new DataModel() { IsSelected = false, Name = "Jane Doe", Age = 39, Mail = "jane@doe-family.com" });
items.Add(new DataModel() { IsSelected = false, Name = "Sammy Doe", Age = 7, Mail = "sammy.doe@gmail.com" });
}
public ObservableCollection<DataModel> Items
{
get
{
return this.items;
}
}
private RelayCommand checkAllCommand;
public ICommand CheckAllCommand
{
get
{
return checkAllCommand ??
(checkAllCommand = new RelayCommand(param => this.SelectUnselectAll(Convert.ToBoolean(param.ToString())))); // <-- this is the line that crashes when trying to convert boolean parameter "param" into boolean. Param is sometimes null, but not always.
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public bool IsSelected
{
get
{
if (this._data == null)
{
return false;
}
return this._data.IsSelected;
}
set
{
if (this._data != null && value != this._data.IsSelected)
{
this._data.IsSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
}
public string Name
{
get
{
if (this._data == null)
{
return string.Empty;
}
return this._data.Name;
}
set
{
if (value != this._data.Name)
{
this._data.Name = value;
NotifyPropertyChanged("Name");
}
}
}
public int Age
{
get
{
if (this._data == null)
{
return 0;
}
return this._data.Age;
}
set
{
if (value != this._data.Age)
{
this._data.Age = value;
NotifyPropertyChanged("Age");
}
}
}
public string Mail
{
get
{
if (this._data == null)
{
return string.Empty;
}
return this._data.Mail;
}
set
{
if (value != this._data.Mail)
{
this._data.Mail = value;
NotifyPropertyChanged("Mail");
}
}
}
private void SelectUnselectAll(bool isSelected)
{
for (int i = 0; i < this.items.Count; i++)
{
if (this.items[i].IsSelected != isSelected)
{
_data = new DataModel()
{
IsSelected = isSelected,
Name = this.items[i].Name,
Age = this.items[i].Age,
Mail = this.items[i].Mail
};
this.items.RemoveAt(i);
this.items.Insert(i, _data);
}
}
}
}
问题在这里,传递给RelayCommand的参数“param”有时为null(并非总是):
private RelayCommand checkAllCommand;
public ICommand CheckAllCommand
{
get
{
return checkAllCommand ??
(checkAllCommand = new RelayCommand(param => this.SelectUnselectAll(Convert.ToBoolean(param.ToString())))); // <-- this is the line that crashes when trying to convert boolean parameter "param" into boolean. Param is sometimes null, but not always.
}
}
我的数据模型:
public class DataModel
{
public bool IsSelected
{
get;
set;
}
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
public string Mail
{
get;
set;
}
}
RelayCommand类:
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
}
知道我为什么会变空?
答案 0 :(得分:0)
在视图模型中不需要超过这个:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ItemData : ViewModelBase
{
public string Name { get; set; }
public string Age { get; set; }
public string Mail { get; set; }
private bool isSelected;
public bool IsSelected
{
get { return isSelected; }
set
{
isSelected = value;
NotifyPropertyChanged();
}
}
}
public class ViewModel : ViewModelBase
{
public ObservableCollection<ItemData> Items { get; }
= new ObservableCollection<ItemData>();
private bool allSelected;
public bool AllSelected
{
get { return allSelected; }
set
{
allSelected = value;
NotifyPropertyChanged();
foreach (var item in Items)
{
item.IsSelected = value;
}
}
}
}
ListView(没有完整的ListViewItem样式):
<ListView ItemsSource="{Binding Items}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.Header>
<CheckBox IsChecked="{Binding AllSelected}"/>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" />
<GridViewColumn Header="Mail" Width="150" DisplayMemberBinding="{Binding Mail}" />
</GridView>
</ListView.View>
</ListView>
答案 1 :(得分:0)
IsChecked
的{{1}}属性确实是CheckBox
,但除非您将Nullable<bool>
属性设置为{,否则它不应该返回null
{1}}。
您可以尝试这种绑定:
IsThreeState
此外,您无需致电true
上的<CheckBox x:Name="CheckAll" Command="{Binding CheckAllCommand}"
CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}" />
即可将其转换为ToString()
。此代码不应该为您提供任何param
:
bool
NullReferenceException
返回private RelayCommand checkAllCommand;
public ICommand CheckAllCommand
{
get
{
return checkAllCommand ??
(checkAllCommand = new RelayCommand(param => this.SelectUnselectAll(Convert.ToBoolean(param))));
}
}
。