none
ComboBoxItem BackgroundColor abhängig vom Wert RRS feed

  • Frage

  • Hallo,

    ich erstelle gerade mit dem EntityFramework und WPF eine Applikation in der ich eine Combox mit Namen füllen lasse. Die Hintergrundfarbe der ComboBoxItem soll dabei je nach Wert unterschiedlich sein.

    z.B.

    Vorname: Theo

    Nachname: Müller

    Wohnort: HH

     

    Vorname: Franz

    Nachname: Meier

    Wohnort: HH

     

    Vorname: Lisa

    Nachname: Schröder

    Wohnort: HB

     

    Nun möchte ich, das die Hintergrundfarbe von Lisa Schröder aus Bremen grün ist, alle anderen (hier Hamburg) weiß.

    Wie kann ich das realisieren? Die Auswahl welcher Wohnort farbig dargestellt wird sollte übrigens dynamisch sein.

    Vom Prinzip würde ich vermuten, dass man ein ControlTemplate für das ComboBoxItem erstellt...?

    Habt ihr Ideen, würde mich sehr freuen.

    DANKE,

    Dru

    Freitag, 17. Juni 2011 12:53

Antworten

  • Hier mal eine kleine Demo:
     
    XAML:
     
    <Window x:Class="Window11"
        Title="Window11" Height="300" Width="300"
        xmlns:app="clr-namespace:WpfApplication1">
      <Window.Resources>
        <app:Window11Converter x:Key="resMyConverter"/>
        <app:Window11Data x:Key="data"/>
       
        <DataTemplate x:Key="myCBTemplate">
          <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="100"/>
              <ColumnDefinition Width="100"/>
              <ColumnDefinition Width="20"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="{Binding Path=Vorname}" />
            <TextBlock Grid.Column="1" Text="{Binding Path=Nachname}"/>
            <TextBlock Grid.Column="2" Text="{Binding Path=Wohnort}"/>
          </Grid>
        </DataTemplate>
     
        <Style x:Key="{x:Type ComboBoxItem}" TargetType="ComboBoxItem">
          <Setter Property = "Background"
                  Value="{Binding Path=Wohnort,
                            Mode=OneWay,
                            Converter={StaticResource resMyConverter},
                            ConverterParameter=HB}"  />
        </Style>
      </Window.Resources>
      <StackPanel>
        <ComboBox ItemsSource="{Binding Source={StaticResource data}}"
                  ItemTemplate="{StaticResource myCBTemplate}"/>
      </StackPanel>
    </Window>
     
    Dazu der Code:
     
    Public Class Window11
     
    End Class
     
    Public Class Window11Data
      Inherits List(Of Window11DataItem)
      Public Sub New()
        Me.Add(New Window11DataItem With {.Vorname = "Theo", ..Nachname = "Müller", .Wohnort = "HH"})
        Me.Add(New Window11DataItem With {.Vorname = "Franz", ..Nachname = "Meier", .Wohnort = "HH"})
        Me.Add(New Window11DataItem With {.Vorname = "Lisa", ..Nachname = "Schröder", .Wohnort = "HB"})
      End Sub
    End Class
     
    Public Class Window11DataItem
      Public Property Vorname As String
      Public Property Nachname As String
      Public Property Wohnort As String
    End Class
     
    Public Class Window11Converter
      Implements IValueConverter
     
      Public Function Convert(ByVal value As Object, _
                              ByVal targetType As System.Type, _
                              ByVal parameter As Object, _
                              ByVal culture As System.Globalization.CultureInfo) _
                            As Object Implements System.Windows.Data.IValueConverter.Convert
        If value.GetType Is GetType(String) Then
          If parameter.ToString = value.ToString() Then
            Return New SolidColorBrush(Colors.Green)
          End If
        End If
        Return New SolidColorBrush(Colors.White)
      End Function
     
      Public Function ConvertBack(ByVal value As Object, _
                                  ByVal targetType As System.Type, _
                                  ByVal parameter As Object, _
                                  ByVal culture As System.Globalization.CultureInfo) _
                                As Object Implements System.Windows.Data.IValueConverter.ConvertBack
        Return value
      End Function
     
    End Class
     
     
    --
    Viele Grüße
    Peter
    • Als Antwort vorgeschlagen Peter Fleischer Samstag, 18. Juni 2011 19:39
    • Als Antwort markiert Dru_MS Samstag, 18. Juni 2011 20:13
    Samstag, 18. Juni 2011 19:38
  • Eine alternative Methode wäre das Hinzufügen zusätzlicher Eigenschaften für die Hintergrundfarbe. Das EntityFramework erstellt partielle Klassen, die im eigenen Code ergänzt werden können. Eine Lösung könnte dann beispielsweise so aussehen:
     
    <Window x:Class="Window11"
        Title="Window11" Height="300" Width="300"
        xmlns:app="clr-namespace:WpfApplication1">
      <Window.Resources>
        <app:Window11Data x:Key="data"/>
       
        <DataTemplate x:Key="myCBTemplate">
          <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="100"/>
              <ColumnDefinition Width="100"/>
              <ColumnDefinition Width="20"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="{Binding Path=Vorname}" />
            <TextBlock Grid.Column="1" Text="{Binding Path=Nachname}"/>
            <TextBlock Grid.Column="2" Text="{Binding Path=Wohnort}"/>
          </Grid>
        </DataTemplate>
     
        <Style x:Key="{x:Type ComboBoxItem}" TargetType="ComboBoxItem">
          <Setter Property = "Background"
                  Value="{Binding Path=Hintergrund, Mode=OneWay}"/>
        </Style>
      </Window.Resources>
      <StackPanel>
        <ComboBox ItemsSource="{Binding Source={StaticResource data}}"
                  ItemTemplate="{StaticResource myCBTemplate}"/>
      </StackPanel>
    </Window>
     
    Dazu der Code:
     
    Public Class Window11
     
    End Class
     
    Public Class Window11Data
      Inherits List(Of Window11DataItem)
      Public Sub New()
        Me.Add(New Window11DataItem With {.Vorname = "Theo", ..Nachname = "Müller", .Wohnort = "HH"})
        Me.Add(New Window11DataItem With {.Vorname = "Franz", ..Nachname = "Meier", .Wohnort = "HH"})
        Me.Add(New Window11DataItem With {.Vorname = "Lisa", ..Nachname = "Schröder", .Wohnort = "HB"})
      End Sub
    End Class
     
    Partial Public Class Window11DataItem
      Public Property Vorname As String
      Public Property Nachname As String
      Public Property Wohnort As String
    End Class
     
    Partial Public Class Window11DataItem
      Public ReadOnly Property Hintergrund As Brush
        Get
          If Me.Wohnort = "HB" Then
            Return New SolidColorBrush(Colors.Green)
          End If
          Return New SolidColorBrush(Colors.White)
        End Get
      End Property
    End Class
     
    Die Beispiele habe ich für die Zukunft auch auf meine Homepage geladen
     
    <Tipps und Tricks - informtools - Tipp 448>
     
    --
    Viele Grüße
    Peter
    • Als Antwort markiert Dru_MS Sonntag, 19. Juni 2011 08:54
    Samstag, 18. Juni 2011 20:35

Alle Antworten

  • Du kannst für das Item sicherlich per Binding die BackgroundColor setzen. Der gebundene Wert kann dann aus deiner Entity-Klasse gebunden werden.

    Das ist allerdings meinst das Problem - die Entities haben bestimmt kein Farb-Attribut. Ich mache sowas dann meist so, das ich eine Klasse definiere, wo alle für die View notwendigen Spezialfälle enthalten sind und die Entities (die z.B. aus einer DB kommen können und unveränderbar sind) als Property enthalten.

    class MyEntity

       prop SolidColorBrush MyColor (kannste anhand des aktuelle EntityItems mit nem Wert befüllen
       prop EntityItem Entity wird mit dem Wert aus der Datenbank gefüllt.

     

    Im Binding beziehst du dich dann auf MyColor bzw. MyEntity.Name.

    Hoffe das hilft dir weiter.

     

     

    Freitag, 17. Juni 2011 13:09
  • Hi, danke für deinen Beitrag, muss ich mal ausprobieren. Wie du schon sagst haben meine Entities kein Farb-Attribut, das ist so gesehen auch gar nicht nötig, denn es gibt nur zwei Farbwerte. Entweder der Wert gehört dazu, dann Farbe1 oder eben nicht, dann Farbe2. Trotzdem danke, ich teste es mal :-)

    Gruß

     

    Freitag, 17. Juni 2011 13:40
  • Hallo zusammen,

    alles was mit der Oberfläche und visuellem (Farben, Controls, etc.) zu tun hat, sollte eigentlich nicht ins ViewModel, sprich sollte keine Bindung zum ViewModel haben. Das ViewModel enthält nur die Logik! Am besten du bindest die Hintergrundfarbe deiner ComboBox an den Wohnort des aktuell gewählten Items und hängst einen Converter, der die Hintergrundfarbe für die ComboBox je nach Eintrag zurückgibt, dazwischen. Somit hast du eine saubere Trennung zwischen View und Model, wie es das MVVM gebietet ;)

    Viele Grüße
    Holger M. Rößler


    Kaum macht man es richtig, schon funktioniert es
    Freitag, 17. Juni 2011 15:03
  • Hi Holger,

    also vorweg, ich arbeite nicht mit dem MVVM ;-) Aber die Idee mit dem Converter find ich ganz gut.

    Hast du nen Beispiel/Ansatz für so einen Converter ?

    DANKE

    Freitag, 17. Juni 2011 15:40
  • Samstag, 18. Juni 2011 13:35
    Beantworter
  • Hier mal eine kleine Demo:
     
    XAML:
     
    <Window x:Class="Window11"
        Title="Window11" Height="300" Width="300"
        xmlns:app="clr-namespace:WpfApplication1">
      <Window.Resources>
        <app:Window11Converter x:Key="resMyConverter"/>
        <app:Window11Data x:Key="data"/>
       
        <DataTemplate x:Key="myCBTemplate">
          <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="100"/>
              <ColumnDefinition Width="100"/>
              <ColumnDefinition Width="20"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="{Binding Path=Vorname}" />
            <TextBlock Grid.Column="1" Text="{Binding Path=Nachname}"/>
            <TextBlock Grid.Column="2" Text="{Binding Path=Wohnort}"/>
          </Grid>
        </DataTemplate>
     
        <Style x:Key="{x:Type ComboBoxItem}" TargetType="ComboBoxItem">
          <Setter Property = "Background"
                  Value="{Binding Path=Wohnort,
                            Mode=OneWay,
                            Converter={StaticResource resMyConverter},
                            ConverterParameter=HB}"  />
        </Style>
      </Window.Resources>
      <StackPanel>
        <ComboBox ItemsSource="{Binding Source={StaticResource data}}"
                  ItemTemplate="{StaticResource myCBTemplate}"/>
      </StackPanel>
    </Window>
     
    Dazu der Code:
     
    Public Class Window11
     
    End Class
     
    Public Class Window11Data
      Inherits List(Of Window11DataItem)
      Public Sub New()
        Me.Add(New Window11DataItem With {.Vorname = "Theo", ..Nachname = "Müller", .Wohnort = "HH"})
        Me.Add(New Window11DataItem With {.Vorname = "Franz", ..Nachname = "Meier", .Wohnort = "HH"})
        Me.Add(New Window11DataItem With {.Vorname = "Lisa", ..Nachname = "Schröder", .Wohnort = "HB"})
      End Sub
    End Class
     
    Public Class Window11DataItem
      Public Property Vorname As String
      Public Property Nachname As String
      Public Property Wohnort As String
    End Class
     
    Public Class Window11Converter
      Implements IValueConverter
     
      Public Function Convert(ByVal value As Object, _
                              ByVal targetType As System.Type, _
                              ByVal parameter As Object, _
                              ByVal culture As System.Globalization.CultureInfo) _
                            As Object Implements System.Windows.Data.IValueConverter.Convert
        If value.GetType Is GetType(String) Then
          If parameter.ToString = value.ToString() Then
            Return New SolidColorBrush(Colors.Green)
          End If
        End If
        Return New SolidColorBrush(Colors.White)
      End Function
     
      Public Function ConvertBack(ByVal value As Object, _
                                  ByVal targetType As System.Type, _
                                  ByVal parameter As Object, _
                                  ByVal culture As System.Globalization.CultureInfo) _
                                As Object Implements System.Windows.Data.IValueConverter.ConvertBack
        Return value
      End Function
     
    End Class
     
     
    --
    Viele Grüße
    Peter
    • Als Antwort vorgeschlagen Peter Fleischer Samstag, 18. Juni 2011 19:39
    • Als Antwort markiert Dru_MS Samstag, 18. Juni 2011 20:13
    Samstag, 18. Juni 2011 19:38
  • Hallo zusammen,

    kann es sein, dass die Benachrichtigungen für die einzelnen Threads nicht mehr funktionieren? Ich bekomme z.Zt. keine Mails mehr bezüglich irgendwelcher Antworten. Gut, Peter hat ja in der Zwischenzeit meinen Vorschlag in Code umgesetzt. Ich hoffe das hilft dir weiter. Ansonsten bitte gezielt fragen... ;o)

    Viele Grüße
    Holger M. Rößler


    Kaum macht man es richtig, schon funktioniert es
    Samstag, 18. Juni 2011 19:59
  • Hallo Holger,

    derzeit musst Du die Benachrichtigung manuell anfordern,
    da die Automatik "ausgefallen" ist, siehe Problem with Forum Alerts

    Gruß Elmar

    Samstag, 18. Juni 2011 20:12
  • Hi Holger,
    ich arbeite mit der MS-Bridge und Windows Live Mail und habe keine Probleme. Benachrichtigungen brauche ich nicht, da ich vorwiegend offline arbeite.
     
    --
    Viele Grüße
    Peter
    Samstag, 18. Juni 2011 20:13
  • Leute,

    ihr seid super ! Vielen Dank für eure Hilfe, eure Vorschläge und auch Demos. Natürlich besonderer Dank an Peter, ich werd da jetzt mal mit C# ausprobieren, VB ist nicht so mein Ding ;-)

    Danke und schönes Wochenende noch !

    Samstag, 18. Juni 2011 20:15
  • Eine alternative Methode wäre das Hinzufügen zusätzlicher Eigenschaften für die Hintergrundfarbe. Das EntityFramework erstellt partielle Klassen, die im eigenen Code ergänzt werden können. Eine Lösung könnte dann beispielsweise so aussehen:
     
    <Window x:Class="Window11"
        Title="Window11" Height="300" Width="300"
        xmlns:app="clr-namespace:WpfApplication1">
      <Window.Resources>
        <app:Window11Data x:Key="data"/>
       
        <DataTemplate x:Key="myCBTemplate">
          <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="100"/>
              <ColumnDefinition Width="100"/>
              <ColumnDefinition Width="20"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="{Binding Path=Vorname}" />
            <TextBlock Grid.Column="1" Text="{Binding Path=Nachname}"/>
            <TextBlock Grid.Column="2" Text="{Binding Path=Wohnort}"/>
          </Grid>
        </DataTemplate>
     
        <Style x:Key="{x:Type ComboBoxItem}" TargetType="ComboBoxItem">
          <Setter Property = "Background"
                  Value="{Binding Path=Hintergrund, Mode=OneWay}"/>
        </Style>
      </Window.Resources>
      <StackPanel>
        <ComboBox ItemsSource="{Binding Source={StaticResource data}}"
                  ItemTemplate="{StaticResource myCBTemplate}"/>
      </StackPanel>
    </Window>
     
    Dazu der Code:
     
    Public Class Window11
     
    End Class
     
    Public Class Window11Data
      Inherits List(Of Window11DataItem)
      Public Sub New()
        Me.Add(New Window11DataItem With {.Vorname = "Theo", ..Nachname = "Müller", .Wohnort = "HH"})
        Me.Add(New Window11DataItem With {.Vorname = "Franz", ..Nachname = "Meier", .Wohnort = "HH"})
        Me.Add(New Window11DataItem With {.Vorname = "Lisa", ..Nachname = "Schröder", .Wohnort = "HB"})
      End Sub
    End Class
     
    Partial Public Class Window11DataItem
      Public Property Vorname As String
      Public Property Nachname As String
      Public Property Wohnort As String
    End Class
     
    Partial Public Class Window11DataItem
      Public ReadOnly Property Hintergrund As Brush
        Get
          If Me.Wohnort = "HB" Then
            Return New SolidColorBrush(Colors.Green)
          End If
          Return New SolidColorBrush(Colors.White)
        End Get
      End Property
    End Class
     
    Die Beispiele habe ich für die Zukunft auch auf meine Homepage geladen
     
    <Tipps und Tricks - informtools - Tipp 448>
     
    --
    Viele Grüße
    Peter
    • Als Antwort markiert Dru_MS Sonntag, 19. Juni 2011 08:54
    Samstag, 18. Juni 2011 20:35
  • Du wirst doch mit der BeginnerASIC-Sprache keine Probleme haben
    --
    Viele Grüße
    Peter
    Samstag, 18. Juni 2011 20:37
  • Nee, ich glaub auch nicht ;-) Ist aber schon ne ganze Zeit lang her. Dank dir nochmal , Peter !
    Sonntag, 19. Juni 2011 08:54
  • Als kleine Ergänzung:

    Ich habe das Ganze jetzt mal für mein Testprojekt umgesetzt. Damit der ConvertParameter nicht statisch ist habe ich den Converter erweitert.

    So kann man die Eigenschaft "aktuellerWohnort" im CodeBehind setzen.

    public class ValueToColorConverter : IValueConverter
    	{
    		
    		//---------------------------------------------------------------
    		private string _aktuellerWohnort;
    
    		public string aktuellerWohnort
    		{
    			get
    			{
    				return _aktuellerWohnort;
    			}
    			set
    			{
    				_aktuellerWohnort = value;
    			}
    		}	
    				
    		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    		{
    			if(aktuellerWohnort == value.ToString())
    			{
    				return new SolidColorBrush(Colors.Green);
    			}
    			return new SolidColorBrush(Colors.White);
    		}
    
    		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    		{
    			return value;
    		}
    	}
    	/// <summary>
    	/// Interaktionslogik für MainWindow.xaml
    	/// </summary>
    	public partial class MainWindow : Window
    	{
    		public MainWindow()
    		{
    			InitializeComponent();
    			ValueToColorConverter v2c = FindResource("myresConverter") as ValueToColorConverter;
    			v2c.aktuellerWohnort = "HH";
    			List<dataItem> dataList = new List<dataItem>();
    			dataList.Add(new dataItem("Theo","Müller","HH"));
    			dataList.Add(new dataItem("Franz", "Meier", "HB"));
    			dataList.Add(new dataItem("Lisa", "Schröder", "HH"));
    			cmbBox.ItemsSource = dataList;
    			
    		}
    	}
    	public class dataItem
    	{
    		public string Vorname { get; set; }
    		public string Nachname { get; set; }
    		public string Wohnort { get; set; }
    
    		public dataItem(string pVorname, string pNachname, string pWohnort)
    		{
    			Vorname = pVorname;
    			Nachname = pNachname;
    			Wohnort = pWohnort;
    		}
    	}
    }
    
    

    <Window.Resources>
        <app:ValueToColorConverter x:Key="myConverter"/>
        <DataTemplate x:Key="myCBTemplate">
          <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="100"/>
              <ColumnDefinition Width="100"/>
              <ColumnDefinition Width="20"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Text="{Binding Path=Vorname}" />
            <TextBlock Grid.Column="1" Text="{Binding Path=Nachname}"/>
            <TextBlock Grid.Column="2" Text="{Binding Path=Wohnort}"/>
          </Grid>
        </DataTemplate>
        <Style x:Key="{x:Type ComboBoxItem}" TargetType="ComboBoxItem">
          <Setter Property = "Background" 
           Value="{Binding Path=Wohnort, 
                Mode=OneWay, 
                Converter={StaticResource myConverter}}" />
        </Style>
      </Window.Resources>
      <Grid>
        <StackPanel>
          <ComboBox x:Name="cmbBox" ItemsSource="{Binding}" 
           ItemTemplate="{StaticResource myCBTemplate}"/>
        </StackPanel>
      </Grid>
    </Window>
    
    
    schönen Sonntag noch !

    Sonntag, 19. Juni 2011 10:59
  • Deine Lösung ist ein möglicher Lösungsweg. Ich würde aber schon den nächsten Schritt gehen und mich am MVVM anlehnen. Das bedeutet, keine Festlegung des Vergleichswertes im Codebehind, sondern (wie in meinem Beispiel) über Parameter, der dann ggf. an eine Eigenschaft im Hintergrund (ViewModel) gebunden wird.
     
    Außerdem kannst Du gern die Objektinitialisierung mit Beschreibung der Eigenschaften anstelle separatem Konstruktor nutzen.
     
    --
    Viele Grüße
    Peter
    Sonntag, 19. Juni 2011 11:17
  • Ich seh schon, ich sollte mich mal intensiv mit dem MVVM beschäftigen. Da komm ich wohl nicht drumrum :-)

    So wie die Lösung momentan ist passt es aber ganz gut, mehr wollte ich eigentlich nicht, was natürlich nicht heissen soll, dass ich nichts mehr dazulernen möchte :-)

    Gruß

    Sonntag, 19. Juni 2011 13:23