以编程方式在Asp.Net ListView中选择项目

6

经过快速搜索,我发现似乎找不到答案,这是一件看起来很简单的事情。

如何在Asp.Net ListView中手动选择一个项目?

我有一个SelectedItemTemplate,但我不想使用asp:button或asp:LinkButton来选择项目。我希望可以通过URL来完成,比如使用QueryString。

我想象的方式是在ItemDataBound事件中检查条件,如果为真,则将其设置为已选中,但我该如何实现呢?

例如:

protected void lv_ItemDataBound(object sender, ListViewItemEventArgs e) {

  using (ListViewDataItem dataItem = (ListViewDataItem)e.Item) {

     if (dataItem != null) {
        if( /* item select condition */ ) {   

            // What do I do here to Set this Item to be Selected?
            // edit: Here's the solution I'm using :
            ((ListView)sender).SelectedIndex = dataItem.DisplayIndex;

            // Note, I get here and it gets set
            // but the SelectedItemTemplate isn't applied!!!

        }
     }
  }
}

我相信这只需要一两行代码。

编辑:我已经更新了代码以反映解决方案,看起来我可以选择ListView的SelectedItemIndex,但实际上它并没有呈现SelectedItemTemplate。我不知道是否应该像下面建议的那样在ItemDataBound事件中完成此操作。

4个回答

13

我查看了ListView底层的一些操作,认为这可能是最佳方法。

void listView_ItemCreated(object sender, ListViewItemEventArgs e)
{
    // exit if we have already selected an item; This is mainly helpful for
    // postbacks, and will also serve to stop processing once we've found our
    // key; Optionally we could remove the ItemCreated event from the ListView 
    // here instead of just returning.
    if ( listView.SelectedIndex > -1 ) return; 

    ListViewDataItem item = e.Item as ListViewDataItem;
    // check to see if the item is the one we want to select (arbitrary) just return true if you want it selected
    if (DoSelectDataItem(item)==true)
    {
        // setting the SelectedIndex is all we really need to do unless 
        // we want to change the template the item will use to render;
        listView.SelectedIndex = item.DisplayIndex;
        if ( listView.SelectedItemTemplate != null )
        {
            // Unfortunately ListView has already a selected a template to use;
            // so clear that out
            e.Item.Controls.Clear();
            // intantiate the SelectedItemTemplate in our item;
            // ListView will DataBind it for us later after ItemCreated has finished!
            listView.SelectedItemTemplate.InstantiateIn(e.Item);
        }
    }
}

bool DoSelectDataItem(ListViewDataItem item)
{
    return item.DisplayIndex == 0; // selects the first item in the list (this is just an example after all; keeping it simple :D )
}

注意事项

  • 在ListView的DataBinding事件触发之后,它会选择一个项目将使用哪个模板。因此,如果在此之前设置SelectedIndex,则不需要再进行其他操作。
  • 在DataBinding之后的任何位置设置SelectedIndex都可以,但你不会得到SelectedItemTemplate。要获取SelectedItemTemplate,你需要重新绑定数据或在ListViewItem上重新实例化SelectedItemTemplate。记得先清除ListViewItem.Controls集合!

更新:我已删除大部分原有解决方案,因为这应该适用于更多情况。


谢谢!我会尝试这个。它似乎是最有前途的解决方案。 - Armstrongest
哇!感谢所有的文档。太棒了!重新实例化SelectedItemTemplate的解决方案非常优雅。 - Armstrongest

5
您可以设置ListView的SelectedIndex。
list.SelectedIndex = dataItem.DisplayIndex; // don't know which index you need
list.SelectedIndex = dataItem.DataItemIndex; 

更新

如果您在页面加载时加载数据,则可能需要遍历数据以查找索引,然后在调用DataBind()方法之前设置SelectedIndex值。

public void Page_Load(object sender, EventArgs e)
{
  var myData = MyDataSource.GetPeople();
  list.DataSource = myData;
  list.SelectedIndex = myData.FirstIndexOf(p => p.Name.Equals("Bob", StringComparison.InvariantCultureIgnoreCase));
  list.DataBind();
}


public static class EnumerableExtensions
{
    public static int FirstIndexOf<T>(this IEnumerable<T> source, Predicate<T> predicate)
    {
        int count = 0;
        foreach(var item in source)
        {
            if (predicate(item))
                return count;
            count++;
        }
        return -1;
    }
}

谢谢!第二种解决方案似乎行不通:list.SelectedValue = dataItem;(list.SelectedValue是只读的)。使用DisplayIndex似乎可以解决问题,但不会改变项目的模板。我这样使用发送器:((ListView)sender).SelectedIndex = dataItem.DisplayIndex; - Armstrongest
看起来你需要在绑定之前设置SelectedIndex?你是在哪里设置ListView的数据源?你使用了DataSourceControl吗?你是通过编程方式设置数据源并调用DataBind的吗? - bendewey
我在PageLoad中设置了数据源。通过对数据层的简单调用,我返回一个List<T>。然后我调用DataBind()。没有DataSourceControl。 - Armstrongest
感谢您的更新。这个方案看起来很不错,应该可以解决问题。虽然我更喜欢将代码封装到ItemCreated方法中的所选方案,但我还是会选择它。再次感谢! - Armstrongest

3
list.SelectedIndex = list.Items.IndexOf(item);

当我在ItemDataBound中设置SelectedIndex时,它似乎没有生效。这是否依赖于ViewState? - Armstrongest

2

在@Jeremy和@bendewey的回答基础上,您不应该在ItemDataBound中执行此操作。在设置SelectedValue之前,您只需要ListView绑定已经完成。您应该能够在PreRender期间执行此操作。有关绑定发生时间的更多信息,请参见此页面生命周期文档


在 PreRender 中这样做有什么优势吗?我通常会在 ItemDataBound 中处理这些事情。我还在这里设置 asp:HyperLink 的 URL。 - Armstrongest
还有一个评论。我设置了这样:((ListView)sender).SelectedIndex = dataItem.DisplayIndex; 但它渲染了标准的ItemTemplate。这是依赖于ViewState还是应该使用PreRender?我现在将会仔细查看页面生命周期文档。 - Armstrongest
如果您需要生命周期,请将此图表挂在您的立方体墙上以供参考。 http://blog.krisvandermast.com/content/binary/ASP.NET-2.0-life-cycle.png - KP.
上面的URL对我不起作用。您可以从Justin的博客这里下载:http://spazzarama.wordpress.com/2009/02/04/aspnet-lifecycle/ - Nick
谢谢。我正在阅读它。 - Armstrongest

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接