具有空行的用户可编辑数据网格,即使 observableCollection 为空
User editable datagrid with empty row, even if observableCollection is empty
我正在使用一个数据网格,通过 TwoWay 绑定绑定到一个 observablecollection。
我的目标是,用户从一个空集合开始生成一个数据列表。
所以我启用了 CanUserAddRow 选项。
在代码中,我使用以下代码生成可观察集合:
private ObservableCollection<Ticket> idlessTicketList = new ObservableCollection<Ticket>();
由 ObservableCollection 组成的 Ticket class 如下所示:
public class Ticket
{
public Ticket() { }
public bool ticketUsed { get; set; }
public string ticketNumber { get; set; }
public string ticketCustomer { get; set; }
public string ticketText { get; set; }
public double ticketTime { get; set; }
public Decimal ticketTypeNr { get; set; }
public string ticketTypeText { get; set; }
}
在 MainWindow 方法中,我将 Datagrid 的 itemSource 设置为我的 ObservableCollection:
public MainWindow()
{
InitializeComponent();
gridIdlessTickets.ItemsSource = idlessTicketList;
}
我现在的问题是,启动时不显示用于添加新行的空行。
如果我通过代码 myGridd.Add(row) 添加新行,则空行会正确显示并且一切正常。
必须如何初始化 ObservableCollection 并正确引用 itemSource?
初始化 itemSource 的最佳位置在哪里?
提前致谢
这应该适合你。让我知道是否有帮助:
XAML:
<Window>
<Grid>
<Datagrid ItemsSource="{Binding idlessTicketList }" SelectionMode="Single" SelectionUnit="Cell" IsReadOnly="False"
CanUserAddRows="True" CanUserDeleteRows="False" AutoGenerateColumns="False">
//ColumnDefinition...etc
<DataGridTextColumn Header="TicketNumber" Binding="{Binding TicketNumber}" />
<DataGridTextColumn Header="TicketCustomer" Binding="{Binding TicketCustomer}"
</Datagrid>
<Button name="ThisIsYourUpdateButton" Command="{Binding UpdateMyTicket}" Width="200" Content="Update me now"/>
</Grid>
</Window>
代码隐藏 (.xaml.cs):
public MainWindow()
{
InitializeComponent(); //parses the XAML...
DataContext = new MainWindowViewModel(); //outsources the view code to the
//"controller" to make the view only display and nothing else...
}
视图模型:(MainWindowViewModel.cs)
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace YourNameSpace
{
public class MainWindowViewModel : INotifyPropertyChanged
{
public ICommand UpdateMyTicket => new DelegateCommand<object>(ExecuteUpdateTicket);
public Ticket TicketInstance {get;set;}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private ObservableCollection<Ticket> _idlessTicketList;
public ObservableCollection<Ticket> idlessTicketList
{
get { return _idlessTicketList; }
set
{
_idlessTicketList = value;
OnPropertyChanged("idlessTicketList");
}
}
//Constructor
public MainWindowViewModel()
{
idlessTicketList = new ObservableCollection<Ticket>();
}
public void ExecuteUpdateTicket(obj param)
{
//if the button is clicked you update your Ticket class properties here!
}
}
}
像这样添加DelegateCommand.cs
class:
using System;
namespace YourNamespaceName
{
public class DelegateCommand<T> : System.Windows.Input.ICommand
{
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public DelegateCommand(Action<T> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<T> execute, Predicate<T> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
return true;
return _canExecute((parameter == null) ? default(T) : (T)Convert.ChangeType(parameter, typeof(T)));
}
public void Execute(object parameter)
{
_execute((parameter == null) ? default(T) : (T)Convert.ChangeType(parameter, typeof(T)));
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
使用单独的视图模型 Class 初始化 observablecollection,空行显示正确。
但是数据不再更新了。
这是我所做的:
我添加了新的 class 作为新的命名空间
xmlns:vm="clr-namespace:nsMainWindowViewModel"
绑定是这样写的:
<DataGrid ItemsSource="{Binding Path=idlessTicketList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Mode=TwoWay, Path=ticketCustomer, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Binding="{Binding Mode=TwoWay, Path=ticketText, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Binding="{Binding Mode=TwoWay, Path=ticketTime, UpdateSourceTrigger=PropertyChanged, StringFormat=\{0:n2\}}"/>
</DataGrid.Columns>
</Datagrid>
使用此实现,PropertyChangedEventHandler 在应用程序启动时被调用,但元素更改时不会被调用。
绑定必须怎么写?
对于我尝试过的数据网格:
{Binding Path=(idlessTicketList), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
{Binding Path=(vm:idlessTicketList), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
{Binding Path=(vm:MainWindowViewModel.idlessTicketList), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
对于我试过的专栏;
{Binding Mode=TwoWay, Path=ticketCustomer, UpdateSourceTrigger=PropertyChanged}
{Binding Mode=TwoWay, Path=(vm:ticketCustomer), UpdateSourceTrigger=PropertyChanged}
{Binding Mode=TwoWay, Path=(vm:MainWindowViewModel.ticketCustomer), UpdateSourceTrigger=PropertyChanged}
调试时,我可以看到最初调用了 PropertyChange 方法,但在编辑单个元素后没有调用。
必须如何定义绑定以更新另一个命名空间中的 te observableCollection?
提前致谢
我正在使用一个数据网格,通过 TwoWay 绑定绑定到一个 observablecollection。 我的目标是,用户从一个空集合开始生成一个数据列表。 所以我启用了 CanUserAddRow 选项。
在代码中,我使用以下代码生成可观察集合:
private ObservableCollection<Ticket> idlessTicketList = new ObservableCollection<Ticket>();
由 ObservableCollection 组成的 Ticket class 如下所示:
public class Ticket
{
public Ticket() { }
public bool ticketUsed { get; set; }
public string ticketNumber { get; set; }
public string ticketCustomer { get; set; }
public string ticketText { get; set; }
public double ticketTime { get; set; }
public Decimal ticketTypeNr { get; set; }
public string ticketTypeText { get; set; }
}
在 MainWindow 方法中,我将 Datagrid 的 itemSource 设置为我的 ObservableCollection:
public MainWindow()
{
InitializeComponent();
gridIdlessTickets.ItemsSource = idlessTicketList;
}
我现在的问题是,启动时不显示用于添加新行的空行。 如果我通过代码 myGridd.Add(row) 添加新行,则空行会正确显示并且一切正常。
必须如何初始化 ObservableCollection 并正确引用 itemSource? 初始化 itemSource 的最佳位置在哪里?
提前致谢
这应该适合你。让我知道是否有帮助:
XAML:
<Window>
<Grid>
<Datagrid ItemsSource="{Binding idlessTicketList }" SelectionMode="Single" SelectionUnit="Cell" IsReadOnly="False"
CanUserAddRows="True" CanUserDeleteRows="False" AutoGenerateColumns="False">
//ColumnDefinition...etc
<DataGridTextColumn Header="TicketNumber" Binding="{Binding TicketNumber}" />
<DataGridTextColumn Header="TicketCustomer" Binding="{Binding TicketCustomer}"
</Datagrid>
<Button name="ThisIsYourUpdateButton" Command="{Binding UpdateMyTicket}" Width="200" Content="Update me now"/>
</Grid>
</Window>
代码隐藏 (.xaml.cs):
public MainWindow()
{
InitializeComponent(); //parses the XAML...
DataContext = new MainWindowViewModel(); //outsources the view code to the
//"controller" to make the view only display and nothing else...
}
视图模型:(MainWindowViewModel.cs)
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace YourNameSpace
{
public class MainWindowViewModel : INotifyPropertyChanged
{
public ICommand UpdateMyTicket => new DelegateCommand<object>(ExecuteUpdateTicket);
public Ticket TicketInstance {get;set;}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private ObservableCollection<Ticket> _idlessTicketList;
public ObservableCollection<Ticket> idlessTicketList
{
get { return _idlessTicketList; }
set
{
_idlessTicketList = value;
OnPropertyChanged("idlessTicketList");
}
}
//Constructor
public MainWindowViewModel()
{
idlessTicketList = new ObservableCollection<Ticket>();
}
public void ExecuteUpdateTicket(obj param)
{
//if the button is clicked you update your Ticket class properties here!
}
}
}
像这样添加DelegateCommand.cs
class:
using System;
namespace YourNamespaceName
{
public class DelegateCommand<T> : System.Windows.Input.ICommand
{
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public DelegateCommand(Action<T> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<T> execute, Predicate<T> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
return true;
return _canExecute((parameter == null) ? default(T) : (T)Convert.ChangeType(parameter, typeof(T)));
}
public void Execute(object parameter)
{
_execute((parameter == null) ? default(T) : (T)Convert.ChangeType(parameter, typeof(T)));
}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
使用单独的视图模型 Class 初始化 observablecollection,空行显示正确。 但是数据不再更新了。 这是我所做的:
我添加了新的 class 作为新的命名空间
xmlns:vm="clr-namespace:nsMainWindowViewModel"
绑定是这样写的:
<DataGrid ItemsSource="{Binding Path=idlessTicketList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Mode=TwoWay, Path=ticketCustomer, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Binding="{Binding Mode=TwoWay, Path=ticketText, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Binding="{Binding Mode=TwoWay, Path=ticketTime, UpdateSourceTrigger=PropertyChanged, StringFormat=\{0:n2\}}"/>
</DataGrid.Columns>
</Datagrid>
使用此实现,PropertyChangedEventHandler 在应用程序启动时被调用,但元素更改时不会被调用。
绑定必须怎么写? 对于我尝试过的数据网格:
{Binding Path=(idlessTicketList), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
{Binding Path=(vm:idlessTicketList), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
{Binding Path=(vm:MainWindowViewModel.idlessTicketList), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
对于我试过的专栏;
{Binding Mode=TwoWay, Path=ticketCustomer, UpdateSourceTrigger=PropertyChanged}
{Binding Mode=TwoWay, Path=(vm:ticketCustomer), UpdateSourceTrigger=PropertyChanged}
{Binding Mode=TwoWay, Path=(vm:MainWindowViewModel.ticketCustomer), UpdateSourceTrigger=PropertyChanged}
调试时,我可以看到最初调用了 PropertyChange 方法,但在编辑单个元素后没有调用。
必须如何定义绑定以更新另一个命名空间中的 te observableCollection?
提前致谢