trouble with changing an item's property in a listbox - c#

I've created a listbox, to which i can add and delete items dynamically UI changes accordingly and it works fine.
<ListBox Name="MsgsList" ItemsSource="{Binding Items}" Style="{StaticResource MsgsBoxStyle}">
<ListBox.ItemTemplate>
<DataTemplate x:Name="MsgsDataTemplate">
<StackPanel Tag="{Binding MsgTagInfo}" ManipulationCompleted="StackPanel_Msgs_ManipulationCompleted">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Hold="GestureListener_Hold" Tap="GestureListener_Tap"/>
</toolkit:GestureService.GestureListener>
<Grid x:Name="ContentPanelInner" Grid.Row="1" Width="500">
<StackPanel x:Name="stackPanelInner" Width="500">
<Grid VerticalAlignment="Top" Width="500">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding MsgTitle}" Style="{StaticResource MsgLine1}" />
<TextBlock Grid.Column="1" Text="{Binding MsgDate}" Style="{StaticResource MsgDate}" />
</Grid>
<TextBlock Text="{Binding MsgBody}" Style="{StaticResource MsgLine2}" />
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
but i didn't understand how to change a style for a particular item's textblock, say based on some condition, if i want to change color of specific item's textbox(s), not sure how to access that.
can somebody please help me with this? thanks.

Probably not the easiest way to do this, but arguably the cleanest from a separation of concerns point of view is by using a converter, and binding that to the property you want to monitor...
For example, if your model is changing state based on a boolean property called myProperty, you could use something like this.
<StackPanel Background={Binding myProperty, Converter={StaticResource myBindingConverter}" />
Your converter should return a SolidColorBrush, based on the value of your property.
public class AlternateRowColour : IValueConverter
{
SolidColorBrush normal = new SolidColorBrush(Colors.Transparent);
SolidColorBrush highlighted = new SolidColorBrush(Color.FromArgb(255, 241, 241, 241));
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var myValue = (bool)value
return myValue ? highlighted : normal ;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}

I If you just want to change on aspect of an items style, for example its color, you could expose that as property of the model object you are binding. For example, add a property TextColor and bind it as follows:
<TextBlock Text="{Binding MsgBody}" Style="{StaticResource MsgLine2}">
<TextBlock.Color>
<SolidColorBrush Color="{Binding TextColor}"/>
</TextBlock.Color>
</TextBlock>
This will take precedence over the colour defined via the style.

Related

Is it possible to use property from ViewModel in attribute, which doesn't support Binding? [duplicate]

This question already has answers here:
Binding an Image in WPF MVVM
(3 answers)
Closed 3 years ago.
I would like to ask, if it is possible to use property from ViewModel in different attribute than for example ItemSource and so on. Example explains the best:
<TextBlock Text="{Binding Name, Mode=TwoWay}" Grid.Column="1">
<TextBlock.ToolTip>
<Image VerticalAlignment="Top" Width="auto" Height="auto" Source="Images/Doc/SomeImage.png"/>
</TextBlock.ToolTip>
</TextBlock>
In this code I would like to use Name (which is used in first line in Binding) as a name of the image - instead of "SomeImage". The purpose of whole this is, that it is item of TreeView and I need to have image for each TextBlock in ToolTip dynamically, based on Name of the item.
So some naive solution will be something like this:
<TextBlock Text="{Binding Name, Mode=TwoWay}" Grid.Column="1">
<TextBlock.ToolTip>
<Image VerticalAlignment="Top" Width="auto" Height="auto" Source="Images/Doc/{Binding Name}.png"/>
</TextBlock.ToolTip>
</TextBlock>
I am searching for solution, how to do it in XAML only, with not touching code behind. If it is even possible?
Thanks a lot for any hint!
You can use StringFormat to format your string like you want without using a converter:
Source="{Binding Name, StringFormat=Images/Doc/{0}.png}"
You can bind the Source property to a view model property:
Source="{Binding Path}"
...but if you want to substitute only a part of the path, you should use a converter:
<TextBlock Text="{Binding Name, Mode=TwoWay}" Grid.Column="1">
<TextBlock.Resources>
<local:Converter x:Key="conv" />
</TextBlock.Resources>
<TextBlock.ToolTip>
<Image VerticalAlignment="Top"
Source="{Binding Name, Converter={StaticResource conv}, ConverterParameter='{}Images/Doc/{0}.png'}" />
</TextBlock.ToolTip>
</TextBlock>
public class Conveter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string name = value as string;
string path = parameter as string;
if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(path))
return new BitmapImage(new Uri(string.Format(path, name), UriKind.Relative));
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}

UWP Bind Listview items foreground to property

I want to change the foreground of certain items in a ListView based on a property of such items. If the item has the property "EsBlacklist" set to true, its foreground should be red.
<Page.Resources>
<converter:ForegroundColorConverter x:Key="ForegroundConverter" x:Name="ForegroundConverter"/>
</Page.Resources>
<StackPanel Grid.Column="1" Grid.Row="1">
<TextBlock HorizontalAlignment="Center" Margin="10" FontSize="24">Vehículos sin VTV</TextBlock>
<ListView ItemsSource="{x:Bind ViewModel.PatentesSinVtv}" Margin="10" DisplayMemberPath="Placa"
SelectedItem="{x:Bind ViewModel.PatenteSeleccionada, Mode=TwoWay}"
HorizontalAlignment="Center"
IsItemClickEnabled="False"
IsSwipeEnabled="False"
CanDragItems="False"
SelectionMode="Single"
Grid.Column="1"
Grid.Row="1">
<ListViewItem Foreground="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource ForegroundConverter}}"></ListViewItem>
( Self should reference the item and not ListViewItem.)
</ListView>
</StackPanel>
And the converter:
class ForegroundColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var patente = (Patente)value; //value is not a Patente but ListViewItem
return patente.EsBlacklist ? new SolidColorBrush(Colors.Red) : new SolidColorBrush(Colors.Gray);
}
}
My problem is that "value" received in the converter is not a Patente but a ListViewItem
My problem is that "value" received in the converter is not a Patente but a ListViewItem
As the document of {RelativeSource} markup extension,
{RelativeSource Self} Produces a Mode value of Self. The target element should be used as the source for this binding. This is useful for binding one property of an element to another property on the same element.
...
The Self mode is useful for binding one property of an element to another property on the same element, and is a variation on ElementName binding but does not require naming and then self-referencing the element.
Here is an example to use the RelativeSource={RelativeSource Self},
<Rectangle
Fill="Orange" Width="200"
Height="{Binding RelativeSource={RelativeSource Self}, Path=Width}"/>
You can see the document to learn how to use {RelativeSource} markup extension
You can bind the ViewModel directly to make the converter be the Patente,
<ListViewItem Foreground="{x:Bind ViewModel, Mode=TwoWay, Converter={StaticResource ForegroundConverter}}"/>
The value of foreground color is not a plain color, but a brush.
So your converter should return new SolidColorBrush(Colors.Red).
You may deal with it like this:
<ListViewItem>
<ListViewItem.Foreground>
<SolidColorBrush Color="{x:Bind YourColor}"/>
</ListViewItem.Foreground>
</ListViewItem>
I needed to implement an ItemTemplate
<ListView.ItemTemplate>
<DataTemplate x:DataType="modelo:Patente">
<TextBlock Text="{Binding Placa}" Foreground="{x:Bind EsBlacklist, Mode=TwoWay, Converter={StaticResource ForegroundConverter}}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
and the converter becomes this:
public object Convert(object value, Type targetType, object parameter, string language)
{
return (bool)value? new SolidColorBrush(Colors.Red) : new SolidColorBrush(Colors.Gray);
}

change SymbolIcon based on Text value

The Need
I'm setting this in a Data Template.. What I want to do is display a different icon per Hardware type with one special exception. The 3 different Icons I will be using are; Shop, OutlineStar, and OtherUser. All Registers will have the Shop Icon, All Servers will have the OutlineStar, and all display boards will have the OtherUser icon.
The Exception
In some cases a register can also be a server, so I would want to switch the Icon to Outline Star in that case.
The Code
<DataTemplate x:Key="ZoomedInTemp"
x:DataType="DeviceMenu">
<Grid>
<StackPanel Orientation="Vertical" Padding="5">
<TextBlock Text="{x:Bind FacilityName}" />
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="Shop" Margin="0,5,12,0"/>
<TextBlock Text="{x:Bind Hardware}" />
<TextBlock Text="{x:Bind HostName}" Margin="10,0,0,0"/>
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
You can use Converter to get the desired symbol and place the logic of getting the symbol based on Hardware in the converter.
Converter
public class SymbolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
// value is Hardware
// Logic to return symbol
//retun Symbol.OutlineStar
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
XAML to use this converter
<DataTemplate x:Key="ZoomedInTemp"
x:DataType="DeviceMenu">
<Grid>
<StackPanel Orientation="Vertical" Padding="5">
<TextBlock Text="{x:Bind FacilityName}" />
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="{x:Bind Hardware, Converter={StaticResource SymbolConverter}}" Margin="0,5,12,0"/>
<TextBlock Text="{x:Bind Hardware}" />
<TextBlock Text="{x:Bind HostName}" Margin="10,0,0,0"/>
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
You will have to add this converter to the page/app level resource.
I am not sure what you will need to decide the Symbol, however, if you need something else also then you can pass that in ConverterParameter.

Simple Arithmetic Operations on Binded Text Property of windows phone 8 app XAML

I'm developing a Windows Phone 8.1 App. In the app I'm parsing a Json data. From the parsed data, I'm populating a GridView. The JsonData consists of temperature in Kelvin. But I want to change the temperature in Celsius while binding the data in the TextBlock.
Here's the Code in XAML
<StackPanel>
<TextBlock x:Name="tblk1" FontSize="20" />
<TextBlock x:Name="tblk2" FontSize="20" Margin="0,5,0,0"/>
<TextBlock x:Name="tblk3" FontSize="20" Margin="0,5,0,0"/>
<ScrollViewer VerticalScrollBarVisibility="Visible" VerticalScrollMode="Enabled" >
<GridView x:Name="tempList" ItemsSource="{Binding}">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10" Background="DarkGreen">
<StackPanel Margin="5">
<TextBlock Text="{Binding dt}" FontSize="15" />
<TextBlock Text="{Binding temp.day}" FontSize="15" />
<TextBlock Text="{Binding temp.min}" FontSize="15" />
<TextBlock Text="{Binding temp.max}" FontSize="15" />
</StackPanel>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</ScrollViewer>
</StackPanel>
And here's code from the C#
protected override void OnNavigatedTo(NavigationEventArgs e)
{
RootObject obj = JsonConvert.DeserializeObject<RootObject>(MainPage.jsonReturn);
tblk1.Text = obj.city.name;
tblk2.Text = obj.cod;
tblk3.Text = obj.message.ToString();
tempList.DataContext = null;
tempList.DataContext = obj.list;
}
In the output, Here the min and max temp is shown in Kelvin. How do I show it in Celsius?
PS There's no any way to change the Incoming JsonData in Celsius. It
has to changed in runtime.
To answer your specific question, it sounds like you want to use a converter with the binding. E.g.:
class KelvinToCelsiusConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value - 273.15;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value + 273.15;
}
}
(Strictly speaking the ConvertBack() method could be left unimplemented, i.e. just throw new NotImplementedException();, but with the above it would also allow for e.g. editable TextBox bindings).
You could then use the above like this, for example:
<TextBlock Text="{Binding Path=temp.day, Converter={StaticResource kelvinToCelsiusConverter1}}" FontSize="15" />
…where you have of course declared the static resource in question, e.g.:
<GridView.Resources>
<local:KelvinToCelsiusConverter x:Key="kelvinToCelsiusConverter1" />
</GridView.Resources>
(I assume here, of course, that you have declared the KelvinToCelsiusConverter class in the namespace which is declared in your XAML as local. Lacking a good, minimal, complete code example, it's impossible to know for sure what all of the above should look like, including namespace declarations).
I also concur with the other observations made by commenter IronSlug:
You should be using binding for all of the displayed data, not just the templated items in your GridView control (i.e. tblk1, tblk2, and tblk3, and any other controls similarly set explicitly in code-behind).
Setting anything to null just before you assign it some different non-null value is pointless.

ValueConverter doesn't work in FlipView

I have a ListView in a FlipView
<FlipView
x:Name="flipView"
AutomationProperties.AutomationId="ItemsFlipView"
AutomationProperties.Name="Item Details"
TabIndex="1"
Width="Auto"
Grid.Row="2"
Grid.Column="1"
VerticalAlignment="Top"
HorizontalAlignment="Center"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}" Padding="0" VirtualizingStackPanel.VirtualizationMode="Standard">
<FlipView.ItemTemplate>
<DataTemplate>
<!--
UserControl chosen as the templated item because it supports visual state management
Loaded/unloaded events explicitly subscribe to view state updates from the page
-->
<UserControl Loaded="StartLayoutUpdates" Unloaded="StopLayoutUpdates">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1" Orientation="Vertical" Margin="0,100,0,0">
<ListView x:Name="ListofOptions" Height="400" Width="280"
ItemsSource="{Binding QuestionOptions}" SelectedValue="{Binding Answer,Mode=TwoWay}"
IsEnabled="{Binding IsEnabled,Mode=TwoWay}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<StackPanel.Resources>
<common:AltBackgroundConverter x:Key="BGConvertor" />
</StackPanel.Resources>
<StackPanel.Background>
<SolidColorBrush Color="{Binding IndexWithinParentCollection, Mode=OneWay, Converter={StaticResource BGConvertor}}"></SolidColorBrush>
</StackPanel.Background>
<TextBlock Text="{Binding OptionValue}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Grid>
</UserControl>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
I write a value conventor of ListView for changing background of alternative row. here is Conventor's code
public class AltBackgroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (!(value is int)) return null;
int index = (int)value;
if (index % 2 == 0)
return Colors.White;
else
return Colors.LightGray;
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
when the listbox is out of FlipView everything is Ok but the Conventor doesn't execute when the ListView is in a FlipView. please advice me.
Created a new Split XAML project in VS2012 and added your converter there and used it in ListView and it was still working after moving the ListView inside a FlipView.
I'm now guessing it's a binding issue, happening because root binding object has changed and one of the bindings not resolved as we expect. have you tried moving the Resources tag to upper level which is the FlipeView?
P.S. This is more of a comment, but I don't have reputation for comments!

Categories

Resources