this is my code, The combo-box control contains text & image :
XAML codes :
<ComboBox Name="cb1"
VerticalAlignment="Center" HorizontalAlignment="Center"
Header="Abcd"
IsEditable="True"
Margin="5"
Width="120">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Icon}" Width="20" Height="20" Margin="5,0,10,0"/>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
C# codes :
public sealed partial class SamplePage2 : Page
{
public SamplePage2()
{
InitializeComponent();
cb1.Items.Add(new Model
{
Icon = new BitmapImage(new Uri("ms-appx:///Assets/Images/mecca.png")),
Text = "بقره"
});
cb1.Items.Add(new Model
{
Icon = new BitmapImage(new Uri("ms-appx:///Assets/Images/medina.png")),
Text = "فاتحه"
});
cb1.SelectedIndex = 0;
}
class Model
{
public BitmapImage Icon { get; set; }
public string Text { get; set; }
}
}
But when I click on the pointer button, or click inside the text..., see this image :
How I can solve this problem?
Note : I need 'IsEditable' feature [ Because I want the user to quickly reach the desired option by writing the text. ]
UWP ComboBox IsEditable does not work right
The problem is the display member is the model class, so it will not editable, for your scenario, we suggest you make a string collection as ComboBox data source. Then us image converter to set image source base on the item's content. For more please refer this case reply.
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image
Width="22"
Height="22"
Source="{Binding Converter={StaticResource ImageConverter}}"
/>
<TextBlock
Margin="10"
Text="{Binding}"
TextAlignment="Center"
/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
private void ComboBox_Loaded(object sender, RoutedEventArgs e)
{
MyComboBox.ItemsSource = new List<string>() { "Red", "Green", "Blue" };
}
Image Converter
public class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
string resaut = string.Empty;
switch (value.ToString())
{
case "Blue":
resaut = "ms-appx:///Assets/BlueImage.png";
break;
case "Green":
resaut = "ms-appx:///Assets/GreenImage.png";
break;
case "Red":
resaut = "ms-appx:///Assets/RedImage.png";
break;
default:
break;
}
return resaut;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
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 want to display multiple rectangles with some properties, which I store in an Array of Arrays. The XAML for displaying looks like this:
<UserControl x:Class="Project.Views.SomeView">
<UserControl.Resources>
<DataTemplate x:Key="ObjectRowTemplate">
<Rectangle Fill="{Binding Path=color, UpdateSourceTrigger=PropertyChanged}" Height="15" Width="30" StrokeThickness="1px" Stroke="Blue" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<catel:EventToCommand DisableAssociatedObjectOnCannotExecute="False">
<catel:EventToCommand.Command>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type Canvas}}" Path="DataContext.ObjectClickedCommand" />
</catel:EventToCommand.Command>
<catel:EventToCommand.CommandParameter>
<Binding Path="." />
</catel:EventToCommand.CommandParameter>
</catel:EventToCommand>
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
</DataTemplate>
<DataTemplate x:Key="ObjectColumnTemplate">
<ItemsControl ItemsSource="{Binding ., UpdateSourceTrigger=PropertyChanged}" ItemTemplate="{DynamicResource ObjectRowTemplate}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</UserControl.Resources>
<StackPanel>
<Canvas Background="Black" Width="{Binding CanvasWidth}" Height="600">
<Grid>
<ItemsControl ItemsSource="{Binding Path=BindedProperty, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" ItemTemplate="{DynamicResource ObjectColumnTemplate}"/>
</Grid>
</Canvas>
</StackPanel>
there is a StackPanel with a canvas inside which shows the array of array via the two defined DataTemplates, by creating a Rectangle for each "slot" in the Array.
namespace ViewModels
{
public class ViewModel : AdvancedViewModelBase
{
public CreateGameFieldViewModel()
{
ObjectClickedCommand = new Command<Object>(ObjectClicked);
Objects = new Objects[15][];
for (int i = 0; i < 15; i++)
{
Objects[i] = new Object[15];
for (int j = 0; j < 15; j++)
{
Objects[i][j] = new Object(someparams);
}
}
}
private Object _selectedObject;
private Object[][] _object;
public Object[][] Objects
{
get { return _object; }
set
{
_object = value;
RaisePropertyChanged(nameof(Objects));
}
}
public int CanvasWidth { get; set; } = 450;
public Command<OPbject> ObjectClickedCommand { get; set; }
public void ObjectClicked(Object object)
{
if (object != null)
{
_selectedObject = object;
}
}
public void OnKeyDown(KeyEventArgs e)
{
// Modify _currentObject
_currentObject.color = Brushes.Blue;
RaisePropertyChanged(nameof(Objects));
}
}
}
The property binding with the viewmodel works fine, the properties are set as defined. By clicking on a Rectangle, the object which is bound to, is now set as _selectedObject and can be modified by the arrow keys, which also works like a charm.
Since I modified one object of the array of arrays, which I am binding to the DataTemplate, I have to notify my UI which I am doing by then line RaisePropertyChanged(nameof(Objects)); (used Nuget: Catel) after the modification.
Unfortunately the UI does not get updated. I checked everything, the object in the array of arrays contains the modifications.
I guess it doesn't work because of the DataTemplates I used.
Can anyone help me?
I am facing the same issue in UWP when the ObservableCollection of the second level of the parent ObservableCollection won't update UI in DataTemplate though it has implemented INotifyPropertyChanged.
It seems like Routing does not work for the nested ObservableCollection.
I also was not able to force the method myObject.OnPropertyChanged('PropertyName').
So the solution was folllowing:
Dynamically populate Tag property of the DataTemplate using ObjectToString converter. So the Tag has a string like Author-3. Where is 3 is the ID of the Author entity and as result we have unique identifiers for all objects created on base of DataTemplate.
Within code just find all objects via Object Type and the Tag name (i.e. Author-3) and do what you need to change its any property.
And you have working UI!
In my case I will provide chunks of code and you will have whole imagination what's going on.
XAML
xmlns:myconverters="using:MyProjectFolder.Converters"
<UserControl.Resources>
<myconverters:LoaderOnlineToColorConverter x:Key="MyLoaderOnlineToColorConverter"/>
<muxc:StackLayout x:Key="UniformGridLayout2" />
<DataTemplate x:Key="UnitLoaderItemTemplate" x:DataType="x1:UnitLoader">
<Grid BorderBrush="Gray" BorderThickness="1" Margin="0,5,0,0" Padding="5,0,5,5" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="6*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel IsDoubleTapEnabled="True" DoubleTapped="Unit_DoubleTapped" Tag="{x:Bind DeviceID}"
Grid.Column="0" Padding="2,0,2,4" Margin="0,5,0,0" Orientation="Horizontal"
BorderBrush="Gray" BorderThickness="1" ToolTipService.ToolTip="{x:Bind FullName}">
<FontIcon Tag="{x:Bind Converter={StaticResource MyDeviceIDToControlNameConverter}}"
Foreground="{x:Bind Converter={StaticResource MyLoaderOnlineToColorConverter}}"
FontFamily="Segoe MDL2 Assets" Glyph="" VerticalAlignment="Center" Margin="0,0,2,0" />
<TextBlock Text="{x:Bind DeviceName}" VerticalAlignment="Center" />
</StackPanel>
NOTE: this line Foreground="{x:Bind Converter={StaticResource MyLoaderOnlineToColorConverter}}" exactly does not work so we have another one
Tag="{x:Bind Converter={StaticResource MyDeviceIDToControlNameConverter}}"
C# The converters
public class DeviceIDToControlNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var controlName = "Unit-";
if (value is UnitLoader)
{
controlName = "Loader-" + ((UnitLoader)value).DeviceID;
}
else if (value is UnitLoader)
{
controlName = "Track-" + ((UnitTrack)value).DeviceID;
}
return controlName;
}
}
public class LoaderOnlineToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
SolidColorBrush color;
if (value is UnitLoader)
{
var isOnline = ((UnitLoader)value).IsOnline;
if (isOnline)
{
color = new SolidColorBrush(Colors.YellowGreen);
}
else
{
color = new SolidColorBrush(Colors.DarkGray);
}
}
else
{
color = new SolidColorBrush(Colors.DarkGray);
}
return color;
}
}
C# The code to change the property of all objects
string tagName = "Loader-" + unitLoader.DeviceID.ToString();
var fontIcon = FindControl<FontIcon>(this, typeof(FontIcon), tagName);
if (fontIcon != null)
{
fontIcon.Foreground = unitLoader.IsOnline ? deviceOnline : deviceOffline;
}
C# Method to search all objects via Type and Tag
public static T FindControl<T>(UIElement parent, Type targetType, string ControlName) where T : FrameworkElement
{
if (parent == null) return null;
if (parent.GetType() == targetType && ((T)parent).Tag != null && ((T)parent).Tag.ToString() == ControlName)
{
return (T)parent;
}
T result = null;
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
if (FindControl<T>(child, targetType, ControlName) != null)
{
result = FindControl<T>(child, targetType, ControlName);
break;
}
}
return result;
}
I have a flipview containing photo, descbox, detailBtn, hideBtn. I would like if the photo tapped, then descbox and hideBtn appear, while detailBtn not appear. And if the photo tapped again, then descbox and hideBtn not appear, while detailBtn looks.
Or if detailBtn clicked, then descbox and hideBtn appear, while detailBtn not appear. And if hideBtn clicked, then descbox and hideBtn not appear, while detailBtn appear.
I'm using the code below:
private async void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
{
var item = await NatureDataSource.GetItemAsync((String)e.NavigationParameter);
var group = await NatureDataSource.GetGroupByItemAsync(item);
this.DefaultViewModel["Group"] = group;
this.DefaultViewModel["Item"] = item;
}
public bool _IsOn;
public bool IsOn
{
get
{
return _IsOn;
}
set
{
_IsOn = value;
}
}
private void photo_Tapped(object sender, TappedRoutedEventArgs e)
{
IsOn = !IsOn;
if (!IsOn)
{
descbox.Visibility = Visibility.Collapsed;
detailBtn.Visibility = Visibility.Visible;
hideBtn.Visibility = Visibility.Collapsed;
}
else
{
descbox.Visibility = Visibility.Visible;
detailBtn.Visibility = Visibility.Collapsed;
hideBtn.Visibility = Visibility.Visible;
}
}
private void detailBtn_Tapped(object sender, TappedRoutedEventArgs e)
{
descbox.Visibility = Visibility.Visible;
detailBtn.Visibility = Visibility.Collapsed;
hideBtn.Visibility = Visibility.Visible;
}
but an error message like the following:
XAML:
<FlipView x:Name="narrowFlipview" Grid.Row="1" ItemsSource="{Binding Group.Items}" SelectedItem="{Binding Item, Mode=TwoWay}" Foreground="{x:Null}">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid x:Name="ContentRoot">
<Grid.ChildrenTransitions>
<TransitionCollection>
<EdgeUIThemeTransition Edge="Left"/>
</TransitionCollection>
</Grid.ChildrenTransitions>
<ScrollViewer x:Name="myScroll" VerticalScrollBarVisibility="Auto" Margin="0,0,0,0" VerticalScrollMode="Auto" HorizontalScrollBarVisibility="Auto" ZoomMode="Enabled" MinZoomFactor="1" HorizontalScrollMode="Auto">
<StackPanel Height="325" Width="558">
<Image x:Name="photo" Source="{Binding ImagePath}" Stretch="Uniform" Height="320" Tapped="photo_Tapped" Margin="0,0,0.333,0" />
<Border x:Name="descbox" Background="#A52C2C2C" Height="120" VerticalAlignment="Bottom" Visibility="Collapsed" Margin="0,-120,0,0">
<ScrollViewer VerticalScrollMode="Auto" Height="auto" HorizontalScrollBarVisibility="Visible">
<StackPanel Width="538">
<TextBlock x:Name="desc" Text="{Binding Description}" FontFamily="verdana" FontSize="17" Foreground="#CCFFFFFF" TextWrapping="Wrap" Padding="0,10" TextAlignment="Justify" Height="auto"/>
</StackPanel>
</ScrollViewer>
</Border>
<Image x:Name="detailBtn" Source="images/media/arrow_up.png" Margin="0,-40,0,0" Height="40" Width="40" HorizontalAlignment="Right" Tapped="detailBtn_Tapped"/>
<Image x:Name="hideBtn" Source="images/media/arrow_down.png" Margin="0,-285,0,0" Height="40" Width="40" HorizontalAlignment="Right" Visibility="Collapsed" Tapped="hideBtn_Tapped"/>
</StackPanel>
</ScrollViewer>
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
How to handle it?
Note:
I tried to use the way in Photo and description on Flipview, but on windows phone 8.1 can not be used
You get the error "descbox" and others don't exist in the current context because they are names of UIElements part of a dataTemplate. The dataTemplate would load only during runtime. The target you want to achieve can be achieved with Data Binding and MVVM concepts far less complexly.
I've created a solution for you based on the data you had provided in the question using Data Binding. I've skipped out the MVVM portion as that is vast enough for an answer. So getting started...
The Updated XAML
based on your code project a few things you could change by putting in the DataBinding for the buttons. like below:
<FlipView x:Name="narrowFlipview" Grid.Row="1" ItemsSource="{Binding Group.Items}" SelectedItem="{Binding Item, Mode=TwoWay}" Foreground="{x:Null}">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid x:Name="ContentRoot">
<Grid.ChildrenTransitions>
<TransitionCollection>
<EdgeUIThemeTransition Edge="Left"/>
</TransitionCollection>
</Grid.ChildrenTransitions>
<ScrollViewer x:Name="myScroll" VerticalScrollBarVisibility="Auto" Margin="0,0,0,0" VerticalScrollMode="Auto" HorizontalScrollBarVisibility="Auto" ZoomMode="Enabled" MinZoomFactor="1" HorizontalScrollMode="Auto">
<StackPanel Height="325" Width="558">
<Image x:Name="photo" Source="{Binding ImagePath}" Stretch="Uniform" Height="320" Tapped="photo_Tapped" Margin="0,0,0.333,0" />
<Border x:Name="descbox" Background="#A52C2C2C" Height="120" VerticalAlignment="Bottom" Visibility="{Binding IsDescriptionVisible,Converter={StaticResource boolToVisibilityConverter}}" Margin="0,-120,0,0">
<ScrollViewer VerticalScrollMode="Auto" Height="auto" HorizontalScrollBarVisibility="Visible">
<StackPanel Width="538">
<TextBlock x:Name="desc" Text="{Binding Description}" FontFamily="verdana" FontSize="17" Foreground="#CCFFFFFF" TextWrapping="Wrap" Padding="0,10" TextAlignment="Justify" Height="auto"/>
</StackPanel>
</ScrollViewer>
</Border>
<AppBarButton x:Name="detailBtn" Icon="Upload" Margin="0,-40,0,0" Height="40" Width="40" HorizontalAlignment="Right" Visibility="{Binding IsDescriptionVisible,Converter={StaticResource boolToInverseVisibilityConverter}}" Click="DetailsBtn_Click"/>
<AppBarButton x:Name="hideBtn" Icon="Download" Margin="0,-285,0,0" Height="40" Width="40" HorizontalAlignment="Right" Visibility="{Binding IsDescriptionVisible,Converter={StaticResource boolToVisibilityConverter}}" Click="HideBtn_Click"/>
</StackPanel>
</ScrollViewer>
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
Note: There are UI fails as the margins are not correct but then that's your code. Try not using Margins for an adaptable layout. you could refer my answer here for more details.
The Code Behind for the same:
I've changed the what to do when the Tapped Event is fired. I've left your code commented for reference reasons. The changes in the Code are as below:
private void photo_Tapped(object sender, TappedRoutedEventArgs e)
{
var currentItem = narrowFlipview.SelectedItem as WaterfallDataItem;
currentItem.IsDataVisible = !currentItem.IsDataVisible;
//IsOn = !IsOn;
//if (!IsOn)
//{
// descbox.Visibility = Visibility.Collapsed;
// detailBtn.Visibility = Visibility.Visible;
// hideBtn.Visibility = Visibility.Collapsed;
//}
//else
//{
// descbox.Visibility = Visibility.Visible;
// detailBtn.Visibility = Visibility.Collapsed;
// hideBtn.Visibility = Visibility.Visible;
//}
}
private void DetailsBtn_Click(object sender, RoutedEventArgs e)
{
var currentItem = narrowFlipview.SelectedItem as WaterfallDataItem;
currentItem.IsDescriptionVisible = true;
}
private void HideBtn_Click(object sender, RoutedEventArgs e)
{
var currentItem = narrowFlipview.SelectedItem as WaterfallDataItem;
currentItem.IsDescriptionVisible = false;
}
The WaterfallDataItem Class Changes:
I've added the Interface INotifyPropertyChanged and added two new properties IsDataVisible and IsDescriptionVisible which raise the PropertyChanged event incase they are changed.
public class WaterfallDataItem:INotifyPropertyChanged
{
public WaterfallDataItem(String uniqueId, String title, String imagePath, String description, String content)
{
this.UniqueId = uniqueId;
this.Title = title;
this.Description = description;
this.ImagePath = imagePath;
this.Content = content;
}
public string UniqueId { get; private set; }
public string Title { get; private set; }
public string Description { get; private set; }
public string ImagePath { get; private set; }
public string Content { get; private set; }
//for the image tap to show description functionality
private bool isDataVisible;
public bool IsDataVisible
{
get { return isDataVisible; }
set
{
isDataVisible = value;
if (value)
IsDescriptionVisible = true;
RaisePropertyChanged("IsDataVisible");
}
}
//for hide and show the details pannel and hide and show content based on that
private bool isDescriptionVisible;
public bool IsDescriptionVisible
{
get { return isDescriptionVisible; }
set { isDescriptionVisible = value; RaisePropertyChanged("IsDescriptionVisible"); }
}
//raises the event to the view if any of these properties change
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public override string ToString()
{
return this.Title;
}
}
Please Note: The PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); Only works with C# 6.0 which is available in Visual Studio 2015. For any editions you will have to use
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
as the new Null Condition operator is only available in C# 6.0. For more information on What's new in c# 6.0 please refer this
The Converter:
The Converter is used to convert the true or false value from the properties to visibility
public class boolToVisibilityConverter : IValueConverter
{
public bool isInverseReq { get; set; }
public object Convert(object value, Type targetType, object parameter, string language)
{
bool val = (bool)value;
if(isInverseReq)
{
if (val)
return Visibility.Collapsed;
else
return Visibility.Visible;
}
else
{
if (val)
return Visibility.Visible;
else
return Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
The App.xaml
Finally to make the converter work we need to add the converter to the app.xaml. Modify the Application.Resources like below:
<Application.Resources>
<local:boolToVisibilityConverter x:Key="boolToVisibilityConverter" isInverseReq="False"/>
<local:boolToVisibilityConverter x:Key="boolToInverseVisibilityConverter" isInverseReq="True"/>
</Application.Resources>
Please note all the classes are simply made in the main project no sub folders, So if you place the classes and converters in some different namespace, do remember to update the xmlns: tag on the xaml
Edit: To Make your solution work:
At the bare minimum you could change a few things in your code to make it work, I have made the changes in the answer. The above changes would let you implement the functionality without changing your code very much. Do let me know if there is anything I missed.
I have an Image in my xaml. That Image gets its source from a Converter. When a click on this image happens it changes the property of the binding source.
What doesn't happen is that the image changes it's source instantly, but if I switch the DataContext of the parent and then switch back to the changed item, it displays just fine.
The xaml:
<conv:BoolImageConverter x:Key="MarkiertImageConverter"/>
[...]
<Border x:Name="maBorder"
DataContext="{Binding SelectedItem, ElementName=myACB, NotifyOnSourceUpdated=True}">
<Grid>
[...]
<StackPanel Orientation="Horizontal"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch">
[...]
<Image x:Name="favImage"
[...]
Source="{Binding Markiert, NotifyOnSourceUpdated=True, Mode=OneWay, Converter={StaticResource MarkiertImageConverter}}"
MouseUp="favImage_MouseUp">
[...]
</Image>
</StackPanel>
</Grid>
</Border>
The Converter:
public class BoolImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool m = (bool)value;
if (m)
{
return new BitmapImage(new Uri(#"/Resources/TrayPopup/bookmark_orange.png",UriKind.Relative));
}
return new BitmapImage(new Uri(#"/Resources/TrayPopup/bookmark_gray.png", UriKind.Relative));
}
[...]
}
The code behind:
private void favImage_MouseUp(object sender, MouseButtonEventArgs e)
{
if ([...])
{
((Kollege)favImage.DataContext).Markiert = !((Kollege)favImage.DataContext).Markiert;
lbFavs.ItemsSource = favColleagueList;
}
}
Why isn't the SourceUpdated for my Image triggered and how can I solve this?
I'm sure this is probably something basic in WPF but I'm new to XAML syntax I'm trying to wrap my head around it.
The Setup
I have a LogItem Type -- just a POCO:
public class LogItem
{
public string Message {get;set;}
public Color MessageColor {get;set;}
}
and a List of LogItem in my ViewModel:
private ObservableCollection<LogItem> _logItems;
public ObservableCollection<LogItem> LogItems
{
get { return _logItems; }
set
{
if (value != _logItems)
{
_logItems = value;
OnPropertyChanged("LogItems");
}
}
}
My viewmodel is bound to the view so that I can do the following:
<ListBox Grid.Row="0" Margin="0,10,0,0" Grid.ColumnSpan="3" Height="150" ItemsSource="{Binding LogItems}">
(Obviously I still have to set the display text binding, etc.)
The Question
Given that I have a Message and MessageColor property in LogItems, what is the correct XAML syntax to bind the color of the item text to the color I specify?
<ListBox Grid.Row="0" Margin="0,10,0,0" Grid.ColumnSpan="3" Height="150" ItemsSource="{Binding LogItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Message}" Foreground="{Binding MessageColor}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
TextBlock Foreground expects a Brush not a Color. Like a lot of things in WPF, There are lot's of ways to approch this. Here is a couple:
Change to MessageColor property in your viewModel to Brush
Brush MessageColor {get;set;}
Create a SolidColorBrush and bind it to your color
<TextBlock Text="{Binding Message}">
<TextBlock.Foreground>
<SolidColorBrush Color="{Binding MessageColor}"/>
</TextBlock.Foreground>
</TextBlock>
Create a ColorToBrushConverter
public class ColorToBrushConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null) return Brushes.Black; // Default color
Color color = (Color)value;
return new SolidColorBrush(color);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
In xaml, create the converter as static resource
<Window.Resources>
<local:ColorToBrushConverter x:Key="colorToBrushConverter"/>
</Window.Resources>
use it in the binding
<TextBlock Text="{Binding Message}" Foreground="{Binding MessageColor, Converter={StaticResource colorToBrushConverter}"/>
Good luck