Программно выбрать элемент в Asp.Net ListView

Asked
Viewd37874

6

Проведя быстрый поиск, я не могу найти ответ на эту, казалось бы, простую вещь.

Как вручную выбрать элемент в Asp.Net ListView?

У меня есть SelectedItemTemplate, но я не хочу использовать asp: button или asp: LinkButton для выбора элемента. Я хочу, чтобы это делалось по URL. Например, как QueryString.

Я предполагаю, что на ItemDataBound нужно проверить условие, а затем установить его как selected, если оно истинно, но как мне это сделать?

Например:

 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!!!

        }
     }
  }
}
 

Я уверен, что это одна или две строки кода.

РЕДАКТИРОВАТЬ: Я обновил код, чтобы отразить решение, и кажется, что я могу выбрать SelectedItemIndex ListView, однако на самом деле он не отображает 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 установлен до этого, больше работать не нужно.
  • Если установить SelectedIndex в любом месте после работы DataBinding, вы просто не получите SelectedItemTemplate. Для этого вам нужно либо заново привязать данные; или повторно создать SelectedItemTemplate в ListViewItem. Обязательно сначала очистите коллекцию ListViewItem.Controls!

ОБНОВЛЕНИЕ Я удалил большую часть своего исходного решения, так как оно должно работать лучше и для большего числа случаев.

  • Wow! Thanks for all the documentation. Great post! Very elegant solution to reinstantiate the SelectedItemTemplate.

    Armstrongest24 февраля 2009, 00:54
  • Thanks! I’m going to try this. It seems to most promising solution.

    Armstrongest20 февраля 2009, 21:24
5

Вы можете установить ListViews SelectedIndex

 list.SelectedIndex = dataItem.DisplayIndex; // don't know which index you need
list.SelectedIndex = dataItem.DataItemIndex; 
 

Обновить

Если вы загружаете данные при загрузке страницы, вам может потребоваться просмотреть данные, чтобы найти индекс, а затем установите значение SelectedIndex перед вызовом метода DataBind ().

 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;
    }
}
 
  • Thanks for the update. A good solution which looks like it would work. I’m going to go with the chosen solution, only because it encapsulates the code into the ItemCreated Method, which I prefer, but thanks!

    Armstrongest24 февраля 2009, 00:59
  • Thanks! It seems the second solution might not work: list.SelectedValue = dataItem; (list.SelectedValue is readonly). Using DisplayIndex seems to work, but doesn’t change the template for the item. I’m using the sender like so: ((ListView)sender).SelectedIndex = dataItem.DisplayIndex;

    Armstrongest20 февраля 2009, 19:32
  • I’m setting the DAtaSource in PageLoad. A simple call to my data layer, where I return a List. Then I call DAtaBind(). No DataSourceControl

    Armstrongest20 февраля 2009, 21:24
  • Seems like your going to have to set your SelectedIndex before binding? How and where are you setting the ListView DataSource? Are you using a DataSourceControl? Are you programmatically setting the DataSource and calling DataBind?

    bendewey20 февраля 2009, 20:08
3
 list.SelectedIndex = list.Items.IndexOf(item);
 
  • When I set the SelectedIndex in ItemDataBound it doesn’t seem to Take. Does this rely on ViewState?

    Armstrongest20 февраля 2009, 19:32
2

Продолжая ответы @Jeremy и @ bendewey, вам не нужно делать это в ItemDataBound. Вам нужно только, чтобы привязка ListView уже была выполнена, прежде чем вы установите SelectedValue. Вы должны иметь возможность сделать это во время PreRender. См. docs жизненный цикл этой страницы для получения дополнительной информации о том, когда происходит привязка. .

  • URL above doesn’t work for me. You can download it from Justin’s blog, here: http://spazzarama.wordpress.com/2009/02/04/aspnet-lifecycle/

    Nick20 февраля 2009, 20:39
  • Also if you need life cycle hang this chart on your cube wall for ref http://blog.krisvandermast.com/content/binary/ASP.NET-2.0-life-cycle.png

    KP.20 февраля 2009, 19:45
  • One more comment. I set it like so: ((ListView)sender).SelectedIndex = dataItem.DisplayIndex; but it renders the standard ItemTemplate. Does this rely on ViewState or should I use PreRender? I will go through the Life Cycle Docs now.

    Armstrongest20 февраля 2009, 19:34
  • Thanks. I’m going through it.

    Armstrongest20 февраля 2009, 22:16
  • Is there an advantage to doing this in PreRender? I usually do these sorts of things in ItemDataBound. I’m also setting the URL of a asp:HyperLink here.

    Armstrongest20 февраля 2009, 19:15