How to highlight ListBox Items matching a certain condition - c#

I have 2 ListBoxes defined thus:
<ListBox Name="aggregatesListBox" SelectionChanged="aggregatesList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Amount}"/>
<TextBlock Text="{Binding Path=AccountId}"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Name="postingsListBox" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=PostingId}" />
<TextBlock Text="{Binding Path=Amount}" />
<TextBlock Text="{Binding Path=CreatedDate}" />
<TextBlock Text="{Binding Path=AccountId}" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I want all items in the postings list to be highlighted (in some way, preferably background colour) if they share the same Account Id as the currently selected aggregated item.
What are my options?
On the advice given I have modified as follows
<ListBox Name="postingsListBox" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<local:IdToBrushConverter x:Key="IdToBrushConverter" />
</StackPanel.Resources>
<StackPanel.Background>
<MultiBinding Converter="{StaticResource IdToBrushConverter}">
<Binding ElementName="aggregatesListBox" Path="SelectedItem.AccountId"/>
<Binding Path="AccountId"/>
</MultiBinding>
</StackPanel.Background>
<TextBlock Text="{Binding Path=PostingId}" />
<TextBlock Text="{Binding Path=Amount}" />
<TextBlock Text="{Binding Path=CreatedDate}"/>
<TextBlock Text="{Binding Path=AccountId}" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and
public class IdToBrushConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
System.Windows.Media.Color colour;
if (values[0] == DependencyProperty.UnsetValue || values[1] == DependencyProperty.UnsetValue || ((int)values[0] != (int)values[1]))
colour = System.Windows.Media.Colors.White;
else
colour = System.Windows.Media.Colors.CornflowerBlue;
return new SolidColorBrush(colour);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException("");
}
}
An attribute on the Window is required so that the brush converter can be located
xmlns:local="clr-namespace:MyAccountingThing"
I also changed the behind the scenes logic to use a list of Objects as the ItemsSource of each of the 2 Listboxes rather than the DataRowView I had previously.
Sorted - Thanks!

You could use a multibinding with a converter, here's an example.
XAML
<ListBox x:Name="list1"
ItemsSource="{Binding List1}">
</ListBox>
<ListBox x:Name="list2"
ItemsSource="{Binding List2}"
Grid.Column="2">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding .}">
<TextBlock.Background>
<MultiBinding Converter="{StaticResource converter}">
<Binding Path="SelectedItem" ElementName="list1"/>
<Binding Path="."/>
</MultiBinding>
</TextBlock.Background>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
On my silly example, I used the MultiBiding to be able to pass more than one parameter to the Converter, which is the selectedItem on the list1 and the currentItem that ListBox2 is applying the Template, next, I used the converter to compare the received values:
Converter:
public class Converter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var selectedValueList1 = values[0];
var currentItemList2 = values[1];
if(selectedValueList1 == null) // Listbox 1 has no selected Item
return Brushes.Black;
if (selectedValueList1 == currentItemList2)
return Brushes.Red;
return Brushes.Transparent;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And of course, you have to elaborate better the test on your converter, in my example I just pass two strings to be compared.
And that is it, it works like expected.

Related

How could I change a textcoroul or a background colour of a TextCell in a ListView on condition

I wonder, how could I change a colour of textcell in a listview by condition. It doesn't matter if it a background color or a textcolor, I just want to highlight some rows depending on condition. My code example below.
<ListView x:Name="lstData" HasUnevenRows="false" Footer="Footer" ItemSelected="OnSelection" >
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding OrderId}" Detail="{Binding OrderState}" />
</DataTemplate>
</ListView.ItemTemplate>
<ListView.FooterTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal" Padding="5,5,5,5">
<Button Text="New Order" Clicked="OnNewOrderClicked" />
</StackLayout>
</DataTemplate>
</ListView.FooterTemplate>
</ListView>
public ManageOrder()
{
InitializeComponent();
var vList = App.orderDatabase.GetAllOrders();
lstData.ItemsSource = vList;
for( int i=0; i < vList.Count(); i++ )
{
if( vList[i].IsDispatched == false )
{
// **Change colour of text view**
}
}
}
<ListView x:Name="lstData" HasUnevenRows="false" Footer="Footer" ItemSelected="OnSelection" >
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding OrderId}" Detail="{Binding OrderState}" TextColor= "{Binding StateColor}" />
</DataTemplate>
</ListView.ItemTemplate>
<ListView.FooterTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal" Padding="5,5,5,5">
<Button Text="New Order" Clicked="OnNewOrderClicked" />
</StackLayout>
</DataTemplate>
</ListView.FooterTemplate>
</ListView>
And in the Order (which is your vlist has) I would have a property with a that is of type Color (the one that is inside xamarin.forms library) which you can control.
Solved it by using Template Selector.
https://developer.xamarin.com/guides/xamarin-forms/templates/data-templates/selector/
You can achieve your requirement by using IValueConverter.
<ContentPage.Resources>
<ResourceDictionary>
<local:Class1 x:Key="class1" />
</ResourceDictionary>
</ContentPage.Resources>
<ListView x:Name="lstData">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding OrderId}" TextColor="{Binding Colors, Converter={StaticResource class1}}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
//Converter class
public class Class1 : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((int)value > 1000)
return Color.Green;
else
return Color.Red;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}

Pass current item to ValueConverter

I have a ListBox where I display all order positions. I need to display a price. I created a ValueConverter which takes a OrderPosition object and returns my price as double.
Formula: Amount * Product.Price (Amount and Product are properties in OrderPosition)
My XAML just won't display anything:
<ListBox Grid.Row="1" Grid.Column="0" Margin="3" ItemsSource="{Binding SelectedOrder.OrderPositions}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}x {1}">
<Binding Path="Amount" />
<Binding Path="Product.Label" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock Text="{Binding /, Converter={StaticResource PositionPriceConverter}, StringFormat={}{0:c}}" Grid.Column="1"
TextAlignment="Right" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here is my converter:
public class PositionPriceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var position = (OrderPosition)value;
return position.Amount * position.Product.Price;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
At the moment you set Path=/ which binds it to CollectionView.CurrentItem
When the source is a collection view, the current item can be specified with a slash (/). For example, the clause Path=/ sets the binding to the current item in the view. When the source is a collection, this syntax specifies the current item of the default collection view.
You can achieve what you're after by setting Path=. or not setting Path altogether.
<TextBlock Text="{Binding Path=., Converter=...}
or
<TextBlock Text="{Binding Converter=...}
but be aware that it will not trigger update when either Amount or Product.Price will change so maybe MultiBinding and IMultiValueConverter would be better option.
I Am not sure if that path you provided to the binding is legal ({Binding /, Converter....).
try to change it in:
<TextBlock Text="{Binding Converter={StaticResource PositionPriceConverter}, StringFormat={}{0:c}}" Grid.Column="1" TextAlignment="Right" />
or
<TextBlock Text="{Binding Path=., Converter={StaticResource PositionPriceConverter}, StringFormat={}{0:c}}" Grid.Column="1" TextAlignment="Right" />
<ListBox Grid.Row="1"
Grid.Column="0"
Margin="3"
ItemsSource="{Binding SelectedOrder.OrderPositions}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}x {1}">
<Binding Path="Amount" />
<Binding Path="Product.Label" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock Grid.Column="1">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource PositionPriceConverter}" StringFormat="{}{0}x {1}">
<Binding Path="Amount" />
<Binding Path="Product.Label" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Change the converter like this,
public class PositionPriceConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var amt = (double)values[0];
var price = (double) values[1];
return amt * price;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Compare ObservableCollection with Toggle Button listBox?

i have listbox taht fill with list of toggle button in after run the project, if i have observablecollection and i want to compare this ObservableCollection with items in list box where if the item in ObservableCollection exist in listbox i want to make this item (toggle button) checked,
i have tryed to do that but i cant access to toggle button in code behind, becouse the list of toggle buttons show after run the project.
here's my listbox code :
<ListBox x:Name="lbname" ItemsSource="{Binding source}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton x:Name="btnitem" Content="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
and my observableCollection :
IQueryable<items> query = _context.items;
ocitems = new ObservableCollection<items>(query);
In short : How can i compare ObservableCollection items with listbox (Buttons) and if item exist in listbox make the Toggle button that represent the item is checked?
hope this clear.
------------------------------------------ More Detail
i have this list box that show choices for selected item, this listBox filled by ObservableCollection "ocSelectedChoice" :
<ListBox x:Name="lbChoices" ItemsSource="{Binding ocSelectedChoice}" DisplayMemberPath="ChoiceName" HorizontalAlignment="Left" Height="165" VerticalAlignment="Top" Width="186" Margin="567,50,0,0" BorderBrush="#FFC1C1C1" Background="#FFE3E3E3" SelectionMode="Extended">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Height" Value="30"/>
<Setter Property="Background" Value="#FFc4d0df"/>
<Setter Property="BorderBrush" Value="#FFC1C1C1"/>
<Setter Property="BorderThickness" Value="0.8"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
when i want to change this item choices, i press the edit button,and will show me windows that has listbox filled by ObservableCollection for all available choices, see the photo, the main problem how to make 'choices 1' lock checked (green one) in choices windows:
<ItemsControl x:Name="icItemGroup" ItemsSource="{Binding PagedSource, ElementName=rdpChoices}" Margin="26,79,0,0" FontWeight="Bold" HorizontalAlignment="Left" Width="506" Height="210" VerticalAlignment="Top" >
<!-- ItemsPanelTemplate -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" HorizontalAlignment="left" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- ItemTemplate -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton x:Name="tbtnChoices" HorizontalAlignment="Left" VerticalAlignment="Top" FontFamily="tahoma" FontSize="12" Height="45" Width="120" FontWeight="Normal" Margin="0,0,0,5" Background="#FFE8E8E8" BorderBrush="#FFC1C1C1" Foreground="#FF6A6A6A"
Content="{Binding ChoiceName}" TabIndex="{Binding ChoicesID}" Click="tbtnChoices_Click">
<ToggleButton.IsChecked>
<MultiBinding Converter="{StaticResource Choices}">
<Binding Path="ocChoice" RelativeSource="{RelativeSource AncestorType={x:Type Window}}"/>
</MultiBinding>
</ToggleButton.IsChecked>
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Converter :
public class ChoicesConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
Choice _choice = values[0] as Choice;
ObservableCollection<Choice> ocChoices = values[1] as ObservableCollection<Choice>;
return ocChoices.Contains(_choice);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture)
{
return null;
}
}
i tried to make this, but sorry still there something unclear for me, please help to solved this issue because it's important for my project.
you should use the multivalue converter to do that i.e bind ToggleButton IsChecked like below:
<ListBox x:Name="lbname" ItemsSource="{Binding source}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton x:Name="btnitem" Content="{Binding Name}">
<ToggleButton.IsChecked>
<MultiBinding Converter="{StaticResource MyConverter}">
<Binding />
<Binding Path="DataContext.ObservableCollectionToCompare" RelativeSource="{RelativeSource AncestorType={x:Type Window}}"/>
</MultiBinding>
</ToggleButton.IsChecked>
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
Here I am assuming that the observalblecollectin to which you want to compare is a property in your view's DataContext.
MyConverter is the multivalue converter that you need to create.
And in the Convert method of your converter you can compare if the item is there in the collection and return true of false accordingly.
public class MyConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
Item listItem = values[0] as Item;
ObservableCollection<Item> collection = values[1] as ObservableCollection<Item>;
return collection.Contains(listItem);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter,
System.Globalization.CultureInfo culture)
{
return null;
}
}
oky, i solved it, here's my code :
This is the converter :
public class IsSelectedChoiceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool _check = false;
if (value == null)
return false;
Item currentItem = (Item)value;
if (currentItem.ChoicesinItem.Count == 0)
_check = false;
foreach (var _choicesinItem in currentItem.ChoicesinItem)
{
if (currentItem.CurrentChoiceId == _choicesinItem.ChoicesId)
_check = true;
}
return _check;
}
and xaml code :
<ToggleButton x:Name="tbtnChoices" HorizontalAlignment="Left" VerticalAlignment="Top" FontFamily="tahoma" FontSize="12" Height="45" Width="120" FontWeight="Normal" Margin="0,0,0,5" Background="#FFE8E8E8" BorderBrush="#FFC1C1C1" Foreground="#FF6A6A6A"
IsChecked="{Binding Path=Item,UpdateSourceTrigger=PropertyChanged, Converter={StaticResource IsSelectedChoice}}"
Content="{Binding Item.CurrentChoiceName}" TabIndex="{Binding Item.CurrentChoiceId}" Click="tbtnChoices_Click">
</ToggleButton>
it's work now, Thanks for anyone help me.

Toggle TextWrapping in TextBox inside FlipView

I have a FlipView where each FlipViewItem contains a TextBox bound to an ObservableCollection and I need to toggle TextWrapping for the TextBox's that are inside the FlipView.
I have tried everything I could think of and no help online thus far. Not a single result I could find.
How can I do this?
XAML:
...
// This part is for the AppBar Toggle button
<ToggleButton x:Name="wordWrapToggleButton" Style="{StaticResource WordWrapAppBarButtonStyle}" />
...
// For the FlipView
<FlipView x:Name="flipView" Grid.Row="1" Margin="0, 50, 0, 0" ItemsSource="{Binding Note, Mode=TwoWay}" Loaded="flipView_Loaded" SelectionChanged="flipView_SelectionChanged" FontSize="12.667">
<FlipView.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Contents, Mode=TwoWay}" Tag="{Binding Title, Mode=TwoWay}" TextWrapping="{Binding ElementName=wordWrapToggleButton, Path=.CheckState, Mode=TwoWay}" IsSpellCheckEnabled="True" AcceptsReturn="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderBrush="{x:Null}" FontSize="{Binding ElementName=flipView, Path=FontSize, Mode=OneWay}" />
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
You have to create a binding converter that converts from bool to TextWrapping
public class BooleanToTextWrappingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (value is bool && (bool)value) ? TextWrapping.Wrap : TextWrapping.NoWrap;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value is TextWrapping && (TextWrapping)value == TextWrapping.Wrap;
}
}
and use that in your binding
<Page.Resources>
<local:BooleanToTextWrappingConverter x:Key="BooleanToTextWrappingConverter"/>
</Page.Resources>
...
<DataTemplate>
<TextBox Text="{Binding Contents, Mode=TwoWay}"
TextWrapping="{Binding Path=IsChecked, ElementName=wordWrapToggleButton,
Converter={StaticResource BooleanToTextWrappingConverter}}"/>
</DataTemplate>
Note that the TextWrapping binding isn't two-way, as that makes no sense.

How to access items in binded listbox, wp7

I have XAML for WP7:
<ListBox x:Name="lbMain" DataContext="{Binding}" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="txtName" Text="{Binding name}" />
<ListBox x:Name="lbCars" DataContext="{Binding}" ItemsSource="{Binding cars}" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="spnlCars">
<TextBlock x:Name="txtCarName" Text="{Binding name}" />
<ListBox x:Name="lbCarColor" DataContext="{Binding}" ItemsSource="{Binding color}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="txtColor" Text="{Binding colorValue}"/>
<Image Name="imgColor"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My DataContex is set to ViewModel I've created, which is getting data from webservice. Data structure is:
Machines (has: Vehicles[])
-Vehicles (has: name, Cars[], Trucks[],...) ----thats what I'm binding to lbMain
--Cars (has: name, color[],...) ---- for example, color[0]="red"
---colorValue
I also have images resources which I want to put in imgColor.
I don't know hot to:
set each imgColor to get different image from resources depending on the txtColor,
apply bold font to txtCarName if (for example) txtColor.Text="red".
I appreciate any advice and any suggestion.
Create a Converter to convert color name into a BitmapImage.
Example :
class ColorToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
String colorName = (String)value;
switch (colorName.ToLower())
{
case "red":
return new BitmapImage(new Uri("..."));
default:
return new BitmapImage(new Uri("..."));
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

Categories