本文介绍了DataGridTemplateColumn(ComboBox,DatePicker)重置/清除并且不触发AddingNewItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经将问题缩小到下面的示例,其中有一个包含三列的DataGrid。



XAML:

 < Window x:Class =DataGridColumnTemplate_NotFiringAddingNewItem.MainWindow
xmlns =http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml
Title =MainWindowHeight =350Width =525>
< Grid>
< DataGrid x:Name =dgHorizo​​ntalAlignment =LeftMargin =10,10,0,0VerticalAlignment =TopHeight =299AutoGenerateColumns =FalseWidth =497 AddingNewItem =dg_AddingNewItemCanUserAddRows =True>
< DataGrid.Columns>
< DataGridTemplateColumn Header =DateWorks>
< DataGridTemplateColumn.CellEditingTemplate>
< DataTemplate>
< DatePicker SelectedDate ={Binding InvoiceDate}/>
< / DataTemplate>
< /DataGridTemplateColumn.CellEditingTemplate>
< / DataGridTemplateColumn>
< DataGridTemplateColumn Header =DateDoesn'tWork>
< DataGridTemplateColumn.CellTemplate>
< DataTemplate>
< DatePicker SelectedDate ={Binding InvoiceDate}/>
< / DataTemplate>
< /DataGridTemplateColumn.CellTemplate>
< DataGridTemplateColumn.CellEditingTemplate>
< DataTemplate>
< DatePicker SelectedDate ={Binding InvoiceDate}/>
< / DataTemplate>
< /DataGridTemplateColumn.CellEditingTemplate>
< / DataGridTemplateColumn>
< DataGridTextColumn Header =TextBinding ={Binding Description}/>
< /DataGrid.Columns>
< / DataGrid>
< / Grid>
< / Window>

C#:

 code> public partial MainWindow:Window 
{
public MainWindow()
{
InitializeComponent();

List< JobCostEntity> l = new List< JobCostEntity>()
{
new JobCostEntity(){Id = 0,InvoiceDate = DateTime.Now,Description =A},
new JobCostEntity = 0,InvoiceDate = DateTime.Now,Description =B}
};

dg.ItemsSource = l;
}
private void dg_AddingNewItem(object sender,AddingNewItemEventArgs e)
{
MessageBox.Show(AddingNewItem);
}
}

public partial class JobCostEntity
{
public int Id {get;组; }
public int JobId {get;组; }
public Nullable< int> JobItemId {get;组; }
public Nullable< System.DateTime> InvoiceDate {get;组; }
public Nullable< System.DateTime> ProcessedDate {get;组; }
public int PackageId {get;组; }
public int DelegateId {get;组; }
public string描述{get;组; }
public Nullable< decimal> LabourCost {get;组; }
public Nullable< decimal> PlantOrMaterialCost {get;组; }
public Nullable< decimal> SubcontractorCost {get;组; }
public Nullable< decimal> TotalCost {get;组; }
public bool Paid {get;组; }
}



如果您在新项目行中点击的第一列是'DateWorks '或'Text',那么你将引发AddingNewItem事件。



如果您首先单击DateDoesntWork列,则可以选择日期,但不会添加新项目,直到您移动到其他列



现在是怎么回事?






需要DatePicker对用户可见(因此CellTemplate和CellEditingTemplate都是可见的),而不是单击单元格来显示控件。



有一些方法,我必须通知DataGrid我的DataGridTemplateColumn控件刚刚在新行上设置一个值?如果是,怎么办?






EDIT:

受此贴子的启发:



我试图通过在DateDoesntWork列DatePicker中添加以下内容来解决问题,这会导致AddingNewItem事件触发,但所选日期仍然不会添加到基础实体。

  private void DateFactory(0,0,0,0,0,0,0,0,0,0,0) ; 
DataGridCell dgc = DataGridHelper.GetCell(dg,GetRowIndex(dg,dgci),GetColIndex(dg,dgci));
dgc.Focus();
dg.BeginEdit();
}

}

尝试定位NewItemPlaceholder,如果这是有意义的?






陌生人,如果你在DateDoesntWork列,然后开始编辑新行上的文本列,然后不输入任何文本,选择上面的行...现在,另一个新行被添加,新添加的行显示我为该行选择的日期!!!



总计。 Madness。






正如Maxime Tremblay-Savard所言,它似乎是 CellTemplate 阻塞下面的'layer',并停止 AddingNewItem 事件触发,虽然内置 DataGridColumn 类型

解决方案

如果你使用一个控件处理鼠标单击CellTemplate,DataGrid从来没有收到点击事件,触发它切换到编辑模式。所以像eoinmullan所提到的,解决方法是设置控件IsHitTestVisible = False。
下面是工作代码。我添加了INotifyPropertyChanged,所以我们可以看到更改的值反映在UI中。我还为DateDoesn'tWork CellTemplate添加了红色背景,因此您可以看到DataGrid何时从显示模式转为编辑模式。

  < Windows x:Class =WpfApplication1.MainWindow
xmlns =http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http:// schemas.microsoft.com/winfx/2006/xaml
Title =MainWindowHeight =350Width =525>
< Grid>
< DataGrid x:Name =dgHorizo​​ntalAlignment =LeftMargin =10,10,0,0VerticalAlignment =TopHeight =299AutoGenerateColumns =FalseWidth =497 AddingNewItem =dg_AddingNewItemCanUserAddRows =True>
< DataGrid.Columns>
< DataGridTemplateColumn Header =DateWorks>
< DataGridTemplateColumn.CellTemplate>
< DataTemplate>
< TextBlock Text ={Binding InvoiceDate}/>

< / DataTemplate>
< /DataGridTemplateColumn.CellTemplate>
< DataGridTemplateColumn.CellEditingTemplate>
< DataTemplate>
< DatePicker SelectedDate ={Binding InvoiceDate}/>
< / DataTemplate>
< /DataGridTemplateColumn.CellEditingTemplate>
< / DataGridTemplateColumn>
< DataGridTemplateColumn Header =DateDoesn'tWork>
< DataGridTemplateColumn.CellTemplate>
< DataTemplate>
<! - 通过使用红色背景>在CellTemplate和CellEditTemplate之间可视化地区分。
< DatePicker Background =RedIsHitTestVisible =FalseSelectedDate ={Binding InvoiceDate}/>
< / DataTemplate>
< /DataGridTemplateColumn.CellTemplate>
< DataGridTemplateColumn.CellEditingTemplate>
< DataTemplate>
< DatePicker SelectedDate ={Binding InvoiceDate}/>
< / DataTemplate>
< /DataGridTemplateColumn.CellEditingTemplate>
< / DataGridTemplateColumn>
< DataGridTextColumn Header =TextBinding ={Binding Description}/>
< /DataGrid.Columns>
< / DataGrid>
< / Grid>
  public partial MainWindow:Window 
{
public MainWindow()
{
InitializeComponent();

List< JobCostEntity> l = new List< JobCostEntity>()
{
new JobCostEntity(){Id = 0,InvoiceDate = DateTime.Now,Description =A},
new JobCostEntity = 0,InvoiceDate = DateTime.Now,Description =B}
};

dg.ItemsSource = l;
}

private void dg_AddingNewItem(object sender,AddingNewItemEventArgs e)
{
//MessageBox.Show(\"AddingNewItem);
}
}

public partial class JobCostEntity:INotifyPropertyChanged
{
private string _description;
private DateTime? _发票日期;

public int Id {get;组; }
public int JobId {get;组; }
public Nullable< int> JobItemId {get;组; }

public Nullable< System.DateTime> InvoiceDate
{
get {return _invoiceDate; }
set
{
if(value.Equals(_invoiceDate))return;
_invoiceDate = value;
OnPropertyChanged();
}
}

public Nullable< System.DateTime> ProcessedDate {get;组; }
public int PackageId {get;组; }
public int DelegateId {get;组; }

public string说明
{
get {return _description; }
set
{
if(value == _description)return;
_description = value;
OnPropertyChanged();
}
}

public Nullable< decimal> LabourCost {get;组; }
public Nullable< decimal> PlantOrMaterialCost {get;组; }
public Nullable< decimal> SubcontractorCost {get;组; }
public Nullable< decimal> TotalCost {get;组; }
public bool Paid {get;组; }

public event PropertyChangedEventHandler PropertyChanged;


protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if(handler!= null)handler(this,new PropertyChangedEventArgs(propertyName));
}
}


I've narrowed down the problem to the following example that has a DataGrid with three columns.

XAML:

<Window x:Class="DataGridColumnTemplate_NotFiringAddingNewItem.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">
    <Grid>
        <DataGrid x:Name="dg" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="299" AutoGenerateColumns="False" Width="497" AddingNewItem="dg_AddingNewItem" CanUserAddRows="True">
            <DataGrid.Columns>
                <DataGridTemplateColumn Header="DateWorks">
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding InvoiceDate}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Header="DateDoesn'tWork">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding InvoiceDate}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                    <DataGridTemplateColumn.CellEditingTemplate>
                        <DataTemplate>
                            <DatePicker SelectedDate="{Binding InvoiceDate}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellEditingTemplate>
                </DataGridTemplateColumn>
                <DataGridTextColumn Header="Text" Binding="{Binding Description}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

C#:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        List<JobCostEntity> l = new List<JobCostEntity>()
        { 
            new JobCostEntity() { Id = 0, InvoiceDate = DateTime.Now, Description = "A"},
            new JobCostEntity() { Id = 0, InvoiceDate = DateTime.Now, Description = "B"}
        };

        dg.ItemsSource = l;
    }
    private void dg_AddingNewItem(object sender, AddingNewItemEventArgs e)
    {
        MessageBox.Show("AddingNewItem");
    }
}

public partial class JobCostEntity
{
    public int Id { get; set; }
    public int JobId { get; set; }
    public Nullable<int> JobItemId { get; set; }
    public Nullable<System.DateTime> InvoiceDate { get; set; }
    public Nullable<System.DateTime> ProcessedDate { get; set; }
    public int PackageId { get; set; }
    public int DelegateId { get; set; }
    public string Description { get; set; }
    public Nullable<decimal> LabourCost { get; set; }
    public Nullable<decimal> PlantOrMaterialCost { get; set; }
    public Nullable<decimal> SubcontractorCost { get; set; }
    public Nullable<decimal> TotalCost { get; set; }
    public bool Paid { get; set; }
}

If the first column you click on in the new item row is 'DateWorks' or 'Text', then you will raise the AddingNewItem event.

If instead you click the 'DateDoesntWork' column first, you can select a date, but no new item is added until you move to one of the other columns, at which point the value in the 'DateDoesntWork' DatePicker gets cleared.

What on earth is going on?


It's arguably(!) desirable to have the DatePicker already visible to the user (hence both a CellTemplate and a CellEditingTemplate), rather than them have to click the cell to 'reveal' the control.

Is there some way I have to inform the DataGrid that my DataGridTemplateColumn Control has just set a value on a new row? If so, how so?!


EDIT:

Inspired by this post: https://social.msdn.microsoft.com/Forums/vstudio/en-US/93d66047-1469-4bed-8fc8-fa5f9bdd2166/programmatically-beginning-edit-in-datagrid-cell?forum=wpf

I have tried to hack my way around the problem by adding the following to the 'DateDoesntWork' column DatePicker, which does cause the AddingNewItem event to fire, but the selected date still doesn't get added to the underlying entity.

private void DatePicker_GotFocus(object sender, RoutedEventArgs e)
{
    if (dg.SelectedIndex == dg.Items.Count - 1)
    {
        DataGridCellInfo dgci = dg.SelectedCells[0];
        DataGridCell dgc = DataGridHelper.GetCell(dg, GetRowIndex(dg, dgci), GetColIndex(dg, dgci));
        dgc.Focus();
        dg.BeginEdit();
    }

}

It seems like the DatePicker is still trying to target the NewItemPlaceholder, if that makes any sense?!


Stranger still, if you select a date in the DateDoesntWork column on the new row, then start editing the Text column on the new row, then without entering any text, select the row above ... now another new row is added and that newly added row shows the date i selected for the row before!!!

Total. Madness.


As Maxime Tremblay-Savard has metioned, it seems like the CellTemplate is blocking the 'layer' below and stopping the AddingNewItem event firing, though the built in DataGridColumn types don't suffer from this problem.

解决方案

If you use a control that handles mouse click within CellTemplate, the DataGrid never receive click event that triggers it to switch to Edit mode. So like eoinmullan mentioned, the solution is to set the control IsHitTestVisible=False.Below is the working code. I added INotifyPropertyChanged so we can actually see the changed value reflected in the UI. I also added red background for DateDoesn'tWork CellTemplate, so you can see when the DataGrid goes from display mode to edit mode.

<Window x:Class="WpfApplication1.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">
<Grid>
    <DataGrid x:Name="dg"  HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="299" AutoGenerateColumns="False" Width="497" AddingNewItem="dg_AddingNewItem" CanUserAddRows="True">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="DateWorks"  >
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding InvoiceDate}"/>

                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <DatePicker SelectedDate="{Binding InvoiceDate}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="DateDoesn'tWork">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate >
                        <!--Differentiate visually between CellTemplate and CellEditTemplate by using red background-->
                        <DatePicker Background="Red" IsHitTestVisible="False" SelectedDate="{Binding InvoiceDate}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <DatePicker SelectedDate="{Binding InvoiceDate}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Header="Text" Binding="{Binding Description}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>
 public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        List<JobCostEntity> l = new List<JobCostEntity>()
        {
            new JobCostEntity() {Id = 0, InvoiceDate = DateTime.Now, Description = "A"},
            new JobCostEntity() {Id = 0, InvoiceDate = DateTime.Now, Description = "B"}
        };

        dg.ItemsSource = l;
    }

    private void dg_AddingNewItem(object sender, AddingNewItemEventArgs e)
    {
        //MessageBox.Show("AddingNewItem");
    }
}

public partial class JobCostEntity : INotifyPropertyChanged
{
    private string _description;
    private DateTime? _invoiceDate;

    public int Id { get; set; }
    public int JobId { get; set; }
    public Nullable<int> JobItemId { get; set; }

    public Nullable<System.DateTime> InvoiceDate
    {
        get { return _invoiceDate; }
        set
        {
            if (value.Equals(_invoiceDate)) return;
            _invoiceDate = value;
            OnPropertyChanged();
        }
    }

    public Nullable<System.DateTime> ProcessedDate { get; set; }
    public int PackageId { get; set; }
    public int DelegateId { get; set; }

    public string Description
    {
        get { return _description; }
        set
        {
            if (value == _description) return;
            _description = value;
            OnPropertyChanged();
        }
    }

    public Nullable<decimal> LabourCost { get; set; }
    public Nullable<decimal> PlantOrMaterialCost { get; set; }
    public Nullable<decimal> SubcontractorCost { get; set; }
    public Nullable<decimal> TotalCost { get; set; }
    public bool Paid { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;


    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

这篇关于DataGridTemplateColumn(ComboBox,DatePicker)重置/清除并且不触发AddingNewItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-01 14:54