I have a ListBox with some items bound to it. Those items are read from files like so:
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
bindList();
}
private void bindList()
{
var appStorage = IsolatedStorageFile.GetUserStoreForApplication();
string[] fileList = appStorage.GetFileNames();
List<Activity> activities = new List<Activity>();
foreach (string file in fileList)
{
string fileName = file;
string cYear = file.Substring(0, 4);
string cMonth = file.Substring(5, 2);
string cDay = file.Substring(8, 2);
string cHour = file.Substring(11, 2);
string cMinute = file.Substring(14, 2);
string cSeconds = file.Substring(17, 2);
DateTime dateCreated = new DateTime(int.Parse(cYear), int.Parse(cMonth), int.Parse(cDay), int.Parse(cHour), int.Parse(cMinute), int.Parse(cSeconds));
string dYear = file.Substring(20, 4);
string dMonth = file.Substring(25, 2);
string dDay = file.Substring(28, 2);
DateTime dateDeadline = new DateTime(int.Parse(dYear), int.Parse(dMonth), int.Parse(dDay));
string aTitle = file.Substring(31);
aTitle = aTitle.Substring(0, aTitle.Length - 4);
activities.Add(new Activity() { Title = aTitle, DateCreated = dateCreated.ToLongDateString(), Deadline = dateDeadline.ToLongDateString(), FileName = fileName });
}
activityListBox.ItemsSource = activities;
}
As you can see I'm reading dates and a title from the file name. Afterwards I bind them to the ListBox. What I want to do is change ListBox item (2 textbox and a hyperlink) color each time the dateDeadline is past the current date.
Here is how my ListBox looks like:
<ListBox HorizontalAlignment="Stretch"
Name="activityListBox"
VerticalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<HyperlinkButton Name="activityTitle"
FontSize="40"
Content="{Binding Title}"
HorizontalContentAlignment="Left"
Tag="{Binding FileName}"
Click="activityTitle_Click"
/>
<TextBlock Name="activityDateCreated"
Text="{Binding DateCreated, StringFormat='Stworzono: {0}'}"
Margin="10" />
<TextBlock Name="activityDeadline"
Text="{Binding Deadline, StringFormat='Deadline: {0}'}"
Margin="10" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Every guide I found was dealing with particular ListBox item (like changing 3rd item, 4th item etc.) and it does not solve my problem. I want to be able to check if the Deadline is past the current date each time files are loaded to the app and change it accordingly.
I'll greatly appreciate your help.
You can use a converter for just such a thing.
<UserControl.Resources>
<ResourceDictionary>
<local:DateToColorConverter x:Key="DateToColorConverter"/>
</ResourceDictionary>
</UserControl.Resources>
...
<TextBlock Name="activityDateCreated"
Text="{Binding DateCreated, StringFormat='Stworzono: {0}'}"
Margin="10"
Foreground="{Binding Deadline, Converter={StaticResource DateToColorConverter}" />
...
Your Converter (put this in your code behind)...
public class DateToColorConverter : IValueConverter
{
static SolidColorBrush _normalColor = new SolidColorBrush(Colors.Black);
static SolidColorBrush _pastDeadlineColor = new SolidColorBrush(Colors.Red);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is DateTime)
{
var deadline = value as DateTime;
return deadline < DateTime.Now ? _pastDeadlineColor : _normalColor;
}
return _normalColor;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
BTW - you should use an ObservableCollection instead of a List to hold your activity objects. Also, make sure your activity object supports INotifyPropertyChanged and that all your property methods call PropertyChanged.
In order to achieve this, you would first want to add a property Forecolor to your Activity class. This property will be a getter property that returns a color based on your condition (In this case, if the current date is greater than the deadline, return Red else Green). Note that I have changed your Deadline data type to Date to allow comparison of dates.
public DateTime Deadline { get; set; }
public Color Forecolor
{
get
{
if (DateTime.Now > Deadline)
return Colors.Red;
else
return Colors.Green;
}
}
Now bind you controls Foreground property to this property Forecolor
Foreground="{Binding Forecolor, Converter={StaticResource ColorToSolidColorBrush_ValueConverter}}"
Since the Foreground property expects a Brush, it will not work with just a color binding, you will need to use a converter that converts a Color to a Brush.
Define a Converter class in your project.
public class ColorToSolidColorBrushValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (null == value)
{
return null;
}
// For a more sophisticated converter, check also the targetType and react accordingly..
if (value is Color)
{
Color color = (Color)value;
return new SolidColorBrush(color);
}
// You can support here more source types if you wish
// For the example I throw an exception
Type type = value.GetType();
throw new InvalidOperationException("Unsupported type [" + type.Name + "]");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// If necessary, here you can convert back. Check if which brush it is (if its one),
// get its Color-value and return it.
throw new NotImplementedException();
}
}
Finally define the converter in your window resources.
<Window.Resources>
<local:ColorToSolidColorBrushValueConverter x:Key="ColorToSolidColorBrush_ValueConverter"/>
</Window.Resources>
Note: I have put in code from a WPF project. There may be a few syntax issues if your project is in WP7 (Though I think, it should work). However the principle is the same.
Related
I had bind the error method property with text-block so that when error occurs it is shown down the textbox in the form. But i also want to change the background color of the textbox when the error occurs. But i don't know how to bind the border-brush property dynamically with text-box when the error occur. I have shared the small portions of my code.
XAML code
<TextBlock
Margin="0 110 0 12"
Style="{StaticResource Label}"
Text="Name"
/>
<TextBox
Margin="0 0 300 0" MaxLength="20" Text="{x:Bind ViewModel.Name, Mode=TwoWay}"
/>
<TextBlock Style="{StaticResource ErrorStyle}" Text="{x:Bind ViewModel.IsNameValid, Mode=TwoWay}"/>
ViewModel
private string IsNameValid_;
public string IsNameValid
{
get => this.IsNameValid_;
set => SetProperty(ref this.IsNameValid_, value);
}
public async Task RegisterPatientInfo()
{
ValidationCheck(this.Name,);
}
ValidationMethod
public void ValidationCheck(string name, string kana, string patientNumber, string year, string month, string days)
{
//Name Validation
var regexNamePattern = #"^([a-zA-Z]){0,20}$";
Regex nameRegex = new Regex(regexNamePattern);
if (!nameRegex.IsMatch(name))
{
this.IsNameValid = "";
}
A common way is to use data-binding with ValueConverter to dynamically change the color of an UIelement.
Here is a simple demo that you could refer to.
ColorConverter:
public class ColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
SolidColorBrush brush = null;
string IsNameValid = value as string;
if (IsNameValid.Equals("123"))
{
brush = new SolidColorBrush(Colors.Red);
}
return brush;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Xaml:
<Page.Resources>
<local:ColorConverter x:Key="ColorConverter"/>
</Page.Resources>
<TextBox Background="{x:Bind ViewModel.IsNameValid,Converter={StaticResource ColorConverter}, Mode=TwoWay}"/>
I have an object based on byte data with over 200 properties that I care about, in the sense that I want to (1) know the value, and (2) know when the value changed from one message to the next.
A snippet of the XAML I am using:
<Label Content="Prop Name" />
<TextBlock Text="{Binding PropName}"
Background="{Binding PropName,
Converter={StaticResource CompareToLastValueConverter}}" />
Currently, I have these lines pasted for EACH property, with appropriate grid location settings.
My question is this: is there a nice way to create a nested WPF UserControl that takes a generic object property from the model and handles assigning the name (with spaces) to the Label, then assigning the value of the property to the TextBlock like the example above?
Also, is this the best way to think about this problem, or am I missing a link in the "WPF way" of doing things?
I've often wanted to try this. I'd create an ItemsControl template for PropertyInfo.
I created a test class:
public class MyClass
{
public string PropertyTest1 {get;set;}
public string PropertyTest2 { get; set; }
public string PropertyTest3 { get; set; }
public string PropertyTest4 { get; set; }
}
To display the properties of. In my data context for the display, I've got two things to bind to. A list of PropertyInfos, and the object in question. Since the PropertyInfo is static, you might be able to do this a better way using a converter or something, and not need to bind it to a property:
public PropertyInfo[] Properties
{
get { return typeof(MyClass).GetProperties(); }
}
public MyClass MyObject
{
get { return new MyClass { PropertyTest1 = "test", PropertyTest3 = "Some string", PropertyTest4 = "Last Property" }; }
}
Now, displaying the properties is easy:
<ItemsControl x:Name="PropertyDisplay" ItemsSource="{Binding Properties}" Grid.IsSharedSizeScope="True">
<ItemsControl.Resources>
<local:PropertyInfoValueConverter x:Key="PropertyInfoValueConverter"/>
</ItemsControl.Resources>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Margin="4,2"/>
<TextBlock Grid.Column="1" Margin="4,2"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But these are 'static', we can't bind to any values. A way to get around that is to use the Tag property, and a multi-binding converter:
So lets add Tag="{Binding MyObject}" to our ItemsSource, and throw that and the PropertyInfo into a value converter for our second textblock:
<TextBlock Grid.Column="1" Margin="4,2">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource PropertyInfoValueConverter}">
<Binding Path=""/>
<Binding ElementName="PropertyDisplay" Path="Tag"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
The converter is actually pretty simple, especially since you're not using text-boxes (so only going the read-only direction):
public class PropertyInfoValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
PropertyInfo propertyInfo = values[0] as PropertyInfo;
return propertyInfo.GetValue(values[1]);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
This is the result:
You say you want spaces for the names, that could be done with a converter with some logic looking for whatever naming convention you've got (spaces before capital letters?).
It would be fun to play with template selectors to choose boolean, string, float templates and treat them differently. (Checkboxes, text, 00.00 formatted text etc)
Edit: Exploring Template Selector
Here's a sample template selector:
public class PropertyInfoTemplateSelector : DataTemplateSelector
{
public DataTemplate StringTemplate { get; set; }
public DataTemplate IntegerTemplate { get; set; }
public DataTemplate DecimalTemplate { get; set; }
public DataTemplate BooleanTemplate { get; set; }
public DataTemplate DefaultTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
PropertyInfo propertyInfo = item as PropertyInfo;
if (propertyInfo.PropertyType == typeof(string))
{
return StringTemplate;
}
else if (propertyInfo.PropertyType == typeof(int))
{
return IntegerTemplate;
}
else if (propertyInfo.PropertyType == typeof(float) || propertyInfo.PropertyType == typeof(double))
{
return DecimalTemplate;
}
else if (propertyInfo.PropertyType == typeof(bool))
{
return BooleanTemplate;
}
return DefaultTemplate;
}
}
Our ItemsControl is now simply:
<ItemsControl x:Name="PropertyDisplay" ItemsSource="{Binding Properties}"
Grid.IsSharedSizeScope="True"
Tag="{Binding MyObject}"
ItemTemplateSelector="{StaticResource PropertyInfoTemplateSelector}"
Margin="20"/>
I also added spaces in names using this converter:
public class PropertyInfoNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string text = value as string;
if (string.IsNullOrWhiteSpace(text))
return string.Empty;
StringBuilder newText = new StringBuilder(text.Length * 2);
newText.Append(text[0]);
for (int i = 1; i < text.Length; i++)
{
if (char.IsUpper(text[i]))
if ((text[i - 1] != ' ' && !char.IsUpper(text[i - 1])) ||
(char.IsUpper(text[i - 1]) &&
i < text.Length - 1 && !char.IsUpper(text[i + 1])))
newText.Append(' ');
newText.Append(text[i]);
}
return newText.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
(Credit to this: https://stackoverflow.com/a/272929/1305699).
Updating our class to contain some boolean and fload fields:
Using a wpf ListBox I'm trying to display a list of filename without displaying the full path (more convenient for user).
Data comes from an ObservableCollection which is filled using Dialog.
private ObservableCollection<string> _VidFileDisplay = new ObservableCollection<string>(new[] {""});
public ObservableCollection<string> VidFileDisplay
{
get { return _VidFileDisplay; }
set { _VidFileDisplay = value; }
}
In the end I want to select some items and get back the full file path. For this I have a converter :
public class PathToFilenameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//return Path.GetFileName(value.ToString());
string result = null;
if (value != null)
{
var path = value.ToString();
if (string.IsNullOrWhiteSpace(path) == false)
result = Path.GetFileName(path);
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
Which I bind to my listbox itemsource :
<ListBox x:Name="VideoFileList" Margin="0" Grid.Row="1" Grid.RowSpan="5" Template="{DynamicResource BaseListBoxControlStyle}" ItemContainerStyle="{DynamicResource BaseListBoxItemStyle}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding Path=DataContext.VidFileDisplay, Converter={StaticResource PathToFileName},ElementName=Ch_Parameters, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding Path=SelectedVidNames,ElementName=Ch_Parameters, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
Without the converter, it is working fine (but of course this is the full path displayed in the listbox). With the converter I have one character per line... displaying this :
System.Collections.ObjectModel.ObservableCollection`1[System.String]
Where am I wrong ?
Thank you
In ItemsSource binding converter applies to the whole list and not to each item in the collection. If you want to apply your converter per item you need to do it ItemTemplate
<ListBox x:Name="VideoFileList" ItemsSource="{Binding Path=DataContext.VidFileDisplay, ElementName=Ch_Parameters}" ...>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=., Converter={StaticResource PathToFileName}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I've got an enum which I use its values as choices in a combo box.
The enum is this:
public enum TimeSizeEnum
{
TENTHSECONDS,
SECONDS,
MINUTES,
HOURS
}
The way I'm binding the values to the combo box:
<ComboBox Grid.Row="4" Grid.Column="1" ItemsSource="{Binding Path=TimeSizeItemsSource, Converter={StaticResource TimerSizeConverter}}" SelectedItem="{Binding Path=TimeSize, Mode=TwoWay}" SelectedIndex="0" Margin="5" MinWidth="100"></ComboBox>
public string[] TimeSizeItemsSource
{
get
{
return Enum.GetNames(typeof(TimeSizeEnum));
}
}
I want that instead of TENTHSECONDS, I'll see "Tenth of a second" or instead of SECONDS, I'll see "Seconds".
How can I achieve that? Is a value converter the best way to do it? But then it means I need to hard-code the strings I want?
I'd recommend using the DescriptionAttribute:
public enum TimeSizeEnum
{
[Description("Tenths of a second")]
TENTHSECONDS,
[Description("Seconds")]
SECONDS,
[Description("Minutes")]
MINUTES,
[Description("Hours")]
HOURS
}
You can then examine the enum value you're passed in a ValueConverter, read the description from the attribute, and display that:
public class TimeSizeEnumDescriptionValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var type = typeof(TimeSizeEnum);
var name = Enum.GetName(type, value);
FieldInfo fi = type.GetField(name);
var descriptionAttrib = (DescriptionAttribute)
Attribute.GetCustomAttribute(fi, typeof(DescriptionAttribute));
return descriptionAttrib.Description;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
To apply the value converter to each enum value, you need to change the combo box's ItemTemplate to include the value converter:
<Window.Resources>
<test:TimeSizeEnumDescriptionValueConverter x:Key="converter" />
</Window.Resources>
<!-- ... -->
<ComboBox ItemsSource="{Binding TimeSizeItemsSource}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<ContentPresenter
Content="{Binding Converter={StaticResource converter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
You can put the attributes on your enum members like
public enum TimeSizeEnum
{
[Description("Tenth of a second")]
TENTHSECONDS,
[Description("Seconds")]
SECONDS,
}
and then you can write a converter which read and return these attributes from the value passed i.e in Convert method of your IValueConveter you can write
var enumtype = typeof(TimeSizeEnum);
var memInfo = enumtype.GetMember(value.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute),
false);
var description = ((DescriptionAttribute)attributes[0]).Description;
return description
I have a class that populates a ListView by passing a list of objects. The class uses reflection to see the properties of each object in order to generate the ListView. How could I change the background color of a row in the ListView.
This page does exactly what I am looking for. The only problem is that my ListView is bound to the list of objects. In other words each item of the ListView is an object that is bound instead of a ListViewItem. I am assuming that is the reason why I cannot cast some item in the ListView to a ListViewItem. For example when I do this:
ListViewItem someItem = (ListViewItem)listView1.Items[0];
I get an InvalidcastException because if I where to physically add the objects to the ListView like:
listview.items.add(someObject) then this will work, but because I am binding the list to the ListView that line does not work. I think that is the reason why I am not able to cast. The reason why I want to cast it is becasue a ListViewItem has a Background property.
EDIT
I am able to do that with the first 12 objects I have tried the folowing:
for (int i = 0; i < listView1.Items.Count; i++)
{
var lvitem = listView1.ItemContainerGenerator.ContainerFromIndex(i) as ListViewItem;
lvitem.Foreground = Brushes.Green;
}
and I get this error:
and I also have tried this:
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;
}
}
and I get the same error:
I don't understand why lvitem is null after the 12 iteration?
It only works with the items that are being displayed....
You need to introduce ViewModels instead of shredding the WPF UI. e.g. I could create one as follows
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... }
}
Next create a list of such objects as a property in your DataContext so that your ListView can bind to it.
// e.g. MainWindow
public IEnumerable<ItemVM> Items { get; set; }
Now all you need to do is bind your ListView to this collection and wire up the DataContext of the UI properly
<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"/>
Now changing the background color is easy. Just set the property of the corresponding ItemVM object to the Color you want. e.g. to set all items to go PaleGreen
private void Button_Click(object sender, RoutedEventArgs e)
{
foreach (var item in Items)
item.BackgroundColor = Colors.PaleGreen;
}
You could use the ItemContainerGenerator, e.g:
var lvitem = listView.ItemContainerGenerator.ContainerFromItem(item) as ListViewItem;
var lvitem = listView.ItemContainerGenerator.ContainerFromIndex(0) as ListViewItem;
However by default the ListView is virtualizing, this means ListViewItems are created on the fly as needed (only if the item is actually visible in the list), so the above methods will not return containers for items which are currently not visible.
This being the case it usually is preferable to define a binding on the Background property via a Setter in the ItemContainerStyle.
When using the ItemContainerGenerator then be aware that the containers are generated asynchronously. The generator exposes a status changed event you could listen to:
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)
{
...
}
}
}
Not sure if that will create any weird drawing effects (flickering) or not.
Another option instead of building the listview items in code is to you use data templates. You might have to add a few properties to your view model for display purposes though.
Assuming the items in your ListBox are of type Foo, and in the ListBox you will display Foo.ItemInfo for each Foo item, and finally let's say there's a property called Status that determines how you want each Foo.ItemInfo to be displayed in the ListBox with respect to the background, foreground, font style, and tooltip text. Based on these requirements, add the following in your 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>
Next, add the following into your MainWindow.xaml.cs (or whatever you've named the XAML's accompanying file) in 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();
}
}
This is one way I've found that works...there's no doubt many other ways, and your mileage may vary...
In any event, HTH
After some googling i found out my own solution
I am using Listview.ItemsSource and as source i use List
Then i can set background of specify ListViewItem in List, and just refresh listview.
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>
Fill ListView with Items with Gray Background:
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; }
}
Create Method for Row Change Color:
private void ChangeRowColor(int RowIndex,SolidColorBrush NewBackground)
{
ITEMS[RowIndex].Background = NewBackground;
listView.Items.Refresh();
}
And use it:
private void button1_Click(object sender, RoutedEventArgs e)
{
ChangeRowColor(4, Brushes.Green);
}
List<ListViewItem> ITEMS = new List<ListViewItem>();
private void loadListView(ListView lv)
{
int numberOfRows = 20;
string[] student_number, first_name, last_name, middle_name, extension, course, year, section;
// ...... Assign values to the arrays above...
for (int h = 0; h <= numberOfRows - 1; h++)
{
ListViewItem OneItem = new ListViewItem();
OneItem.Background = course[h] == "Grade" ? Brushes.Red : Brushes.Transparent; //Decide the color of the Row
OneItem.Content = new Student
{
Student_Number = student_number[h],
Course = course[h],
Section = section[h],
Year = year[h],
FullName = first_name[h] + " " + middle_name[h] + ". " + last_name[h] + " " + extension[h]
};
ITEMS.Add(OneItem);
lv.ItemsSource = ITEMS;
}
lv.Items.Refresh();
}
public class Student
{
public string Student_Number { get; set; }
public string FullName { get; set; }
public string Course { get; set; }
public string Section { get; set; }
public string Year { get; set; }
}
output screenshot