2011-05-30 68 views
8

Tengo una clase que rellena un ListView al pasar una lista de objetos. La clase usa la reflexión para ver las propiedades de cada objeto para generar el ListView. ¿Cómo podría cambiar el color de fondo de una fila en el ListView?Cambiar el color de fondo de la fila ListView mediante programación (wpf)

Esto page hace exactamente lo que estoy buscando. El único problema es que mi ListView está vinculado a la lista de objetos. En otras palabras, cada elemento de ListView es un objeto vinculado en lugar de un ListViewItem. Supongo que esa es la razón por la que no puedo convertir ningún elemento en el ListView en un ListViewItem. Por ejemplo cuando hago esto:

ListViewItem someItem = (ListViewItem)listView1.Items[0]; 

consigo un InvalidCastException porque si yo dónde agregar físicamente los objetos al ListView como:

listview.items.add (someObject) entonces esto va a funcionar, pero porque estoy vinculando la lista al ListView, esa línea no funciona. Creo que esa es la razón por la que no soy capaz de lanzar. La razón por la que deseo lanzarlo es porque ListViewItem tiene una propiedad de Fondo.

EDITAR

soy capaz de hacer eso con los primeros 12 objetos He probado el folowing:

for (int i = 0; i < listView1.Items.Count; i++) 
{ 
    var lvitem = listView1.ItemContainerGenerator.ContainerFromIndex(i) as ListViewItem; 
    lvitem.Foreground = Brushes.Green;     
} 

y me sale este error:

first try

y yo también lo han intentado esto:

foreach (Tiro t in listView1.Items) 
{ 
    var lvitem = listView1.ItemContainerGenerator.ContainerFromItem(t) as ListViewItem; 
    if (t.numero == 0 || t.numero == 37) 
    { 
     //lvitem.Background = Brushes.Green; 
     lvitem.Foreground = Brushes.Green; 
    } 
    else if (t.numero % 2 == 0) 
    { 
     //lvitem.Background = Brushes.Red; 
     lvitem.Foreground = Brushes.Red; 
    } 
    else 
    { 
     //lvitem.Background = Brushes.Gray; 
     lvitem.Foreground = Brushes.Black; 
    } 

} 

y me sale el mismo error:

enter image description here

No entiendo por qué LVITEM es nulo después de la iteración 12?

Sólo funciona con los elementos que se están exhibiendo ....

Respuesta

3

Al usar el ItemContainerGenerator, tenga en cuenta que los contenedores se generan de forma asíncrona. El generador expone un evento de cambio de estado se podía escuchar:

listView.ItemContainerGenerator.StatusChanged += new EventHandler(ContainerStatusChanged);  

private void ContainerStatusChanged(object sender, EventArgs e) 
{ 
    if (listView.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) 
    { 
     foreach (Tiro t in listView1.Items) 
     { 
      ... 
     } 
    } 
} 

No estoy seguro de si eso va a crear efectos extraños de dibujo (parpadeo) o no.

Otra opción en vez de compilar los elementos listview en código es utilizar plantillas de datos.Sin embargo, es posible que tenga que agregar algunas propiedades a su modelo de visualización para fines de visualización.

3

Se podría utilizar el ItemContainerGenerator, por ejemplo:

var lvitem = listView.ItemContainerGenerator.ContainerFromItem(item) as ListViewItem; 
var lvitem = listView.ItemContainerGenerator.ContainerFromIndex(0) as ListViewItem; 

Sin embargo por defecto el ListView está virtualizando, esto significa que se crean ListViewItems sobre la marcha según sea necesario (solo si el artículo es realmente visible en la lista), por lo que los métodos anteriores no devolverán contenedores para artículos que actualmente no están visibles.

En este caso, generalmente es preferible definir una vinculación en la propiedad Background a través de Setter en el ItemContainerStyle.

+0

Ahora puedo hacer más cosas gracias. Sin embargo, no puedo cambiar el color. Seguiré intentando. –

+0

lvitem.Background = Brushes.AliceBlue; Necesitaba usar Bush en lugar de Colors –

+0

Bueno, eso es algo de sentido común. –

9

Debe presentar ViewModels en lugar de triturar la interfaz de usuario de WPF. p.ej. Podría crear uno de la siguiente manera

public class ItemVM : INotifyPropertyChanged // if you want runtime changes to be reflected in the UI 
{ 
    public string Text {... raise property change in setter } 
    public Color BackgroundColor {... ditto... } 
} 

A continuación, cree una lista de objetos tales como una propiedad en sus DataContext para que su ListView puede unirse a ella.

// e.g. MainWindow 
    public IEnumerable<ItemVM> Items { get; set; } 

Ahora todo lo que necesita hacer es vincular a su ListView a esta colección y cable hasta el DataContext de la interfaz de usuario adecuada

 <ListView x:Name="MyListView" ItemsSource="{Binding Items}" HorizontalContentAlignment="Stretch"> 
      <ListView.ItemTemplate> 
       <DataTemplate> 
        <TextBlock Text="{Binding Text}"> 
        <TextBlock.Background> 
         <SolidColorBrush Color="{Binding BackgroundColor}"/> 
        </TextBlock.Background> 
        </TextBlock> 
       </DataTemplate> 
      </ListView.ItemTemplate> 
     </ListView> 
     <Button Click="Button_Click" Content="Go PaleGreen"/> 

cambiando el color de fondo es fácil. Simplemente establezca la propiedad del objeto ItemVM correspondiente al color que desee. p.ej. para establecer todos los elementos para ir Palegreen

private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     foreach (var item in Items) 
      item.BackgroundColor = Colors.PaleGreen; 
    } 
+0

Gracias, está funcionando ... gracias por publicar una respuesta –

1

Suponiendo que los artículos en su cuadro de lista es de tipo Foo, y en el cuadro de lista se mostrará Foo.ItemInfo para cada elemento de Foo, y, finalmente, digamos que hay una propiedad llamada Estado que determina cómo desea que cada Foo.ItemInfo se muestre en el ListBox con respecto al fondo, primer plano, estilo de fuente y texto de información sobre herramientas. Sobre la base de estos requisitos, añadir lo siguiente en su XAML:

<ListBox FontFamily="Courier New" 
     HorizontalAlignment="Left" 
     ... 
     ...other ListBox attributes... 
     ... 
    <ListBox.Resources> 
     <local:BGConverter x:Key="BackgroundConverter"/> 
     <local:FGConverter x:Key="ForegroundConverter"/> 
     <local:FSConverter x:Key="FontStyleConverter"/> 
     <local:TTConverter x:Key="ToolTipConverter"/> 
    </ListBox.Resources> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding ItemInfo}" 
       Background="{Binding Converter={StaticResource BackgroundConverter}}" 
       FontStyle="{Binding Converter={StaticResource FontStyleConverter}}" 
       Foreground="{Binding Converter={StaticResource ForegroundConverter}}" 
       ToolTip="{Binding Converter={StaticResource ToolTipConverter}}" /> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

A continuación, añadir lo siguiente en sus MainWindow.xaml.cs (o lo que hemos llamado el archivo que acompaña al XAML) en C#:

public class BGConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     Foo foo = (Foo)value; 
     string bgColor = "Gray"; 

     switch(foo.Status) 
     { 
      case 0: 
       bgColor = "White"; 
       break; 

      case 1: 
       bgColor = "Cyan"; 
       break; 

      case 2: 
       bgColor = "Yellow"; 
       break; 
     } 

     return bgColor; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class FSConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     Foo foo = (Foo)value; 
     string fStyle = "Normal"; 

     switch(foo.Status) 
     { 
      case 0: 
       fStyle = "Normal"; 
       break; 

      case 1: 
       fStyle = "Oblique"; 
       break; 

      case 2: 
       fStyle = "Italic"; 
       break; 
     } 

     return fStyle; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 


public class FGConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     Foo foo = (Foo)value; 
     string fgColor = "Black"; 

     switch(foo.Status) 
     { 
      case 0: 
       fgColor = "Blue"; 
       break; 

      case 1: 
       fgColor = "Brown"; 
       break; 

      case 2: 
       fgColor = "DarkBlue"; 
       break; 
     } 

     return fgColor; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class TTipConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     Foo foo = (Foo)value; 
     string ttText = "No tool tips for this item."; 

     switch(foo.Status) 
     { 
      case 0: 
       ttText = "The item has not been processed"; 
       break; 

      case 1: 
       ttText = "The item has been processed but not saved"; 
       break; 

      case 2: 
       ttText = "The item has been processed and saved"; 
       break; 
     } 

     return ttText ; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Ésta es una manera que he encontrado que funciona ... no hay duda de muchas otras maneras, y su experiencia puede variar ...

En cualquier caso, HTH

1

Después de algunas google me enteré mi propia solución Estoy usando Listview.ItemsSource y como fuente utilizo List Luego puedo establecer el fondo de especificar ListViewItem en List, y simplemente actualizar la vista de lista.

XAML:

<ListView x:Name="listView" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.Row="1"> 
       <ListView.View> 
        <GridView> 
         <GridViewColumn Header="IP" DisplayMemberBinding="{Binding IP}" Width="Auto"/> 
         <GridViewColumn Header="PING" DisplayMemberBinding="{Binding Ping}" Width="Auto"/> 
         <GridViewColumn Header="Host Name" DisplayMemberBinding="{Binding DNS}" Width="Auto"/> 
         <GridViewColumn Header="Mac" DisplayMemberBinding="{Binding MAC}" Width="Auto"/> 
         <GridViewColumn Header="Výrobce" DisplayMemberBinding="{Binding Manufacturer}" Width="Auto"/> 
        </GridView> 
       </ListView.View> 
      </ListView> 

ListView de relleno con artículos con fondo gris:

List<ListViewItem> ITEMS = new List<ListViewItem>(); 
    private void button_Click(object sender, RoutedEventArgs e) 
    { 
     for (int i = 1; i < 20; i++) 
     { 
      ListViewItem OneItem = new ListViewItem(); 
      OneItem.Background = Brushes.LightGray; 
      OneItem.Content = new Device() { IP = "1.1.1.1", Ping = "30ms", DNS = "XYZ", MAC = "2F:3C:5F:41:F9", Manufacturer = "Intel" }; 
      ITEMS.Add(OneItem); 
      listView.ItemsSource = ITEMS; 
     } 
     listView.Items.Refresh(); 
    } 
    public class Device 
    { 
     public string IP { get; set; } 
     public string Ping { get; set; } 
     public string DNS { get; set; } 
     public string MAC { get; set; } 
     public string Manufacturer { get; set; } 
    } 

Crear Método para la fila Cambio de color:

private void ChangeRowColor(int RowIndex,SolidColorBrush NewBackground) 
    { 
     ITEMS[RowIndex].Background = NewBackground; 
     listView.Items.Refresh(); 
    } 

y utilizarla:

private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     ChangeRowColor(4, Brushes.Green); 
    } 
Cuestiones relacionadas