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?
Related
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();
}
}
I created a ComboBox listing the colors that System.Windows.Media.Colors predefines, using the approach told in this question: How can I list colors in WPF with XAML?
My XAML code now is:
<Window ...>
<Window.Resources>
<ObjectDataProvider
ObjectInstance="{x:Type Colors}" MethodName="GetProperties" x:Key="ColorList" />
<local:StringToBrushConverter x:Key="FontColorConversions" />
</Window.Resources>
<Grid Background="Black">
...
<ComboBox Grid.Column="1" Grid.Row="1" Height="22" Width="240"
VerticalAlignment="Center" HorizontalAlignment="Left"
ItemsSource="{Binding Source={StaticResource ColorList}}"
SelectedValue="{Binding FontColor, Mode=TwoWay}"
DisplayMemberPath="Name"
SelectedValuePath="Name">
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="Foreground" Value="{Binding Converter={StaticResource FontColorConversions}}"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
...
</Grid>
</Window>
And besides, please note that I bind SelectedValue to a VM class's FontColor property, which is of string type.
class FontSetting : INotifyPropertyChanged
{
private string _fontColor = "Lavender"; // initial color
public event PropertyChangedEventHandler PropertyChanged;
public string FontColor
{
get
{
return _fontColor;
}
set
{
_fontColor = value;
OnPropertyChanged("FontColor");
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And I set the DataContext of the Window containing this ComboBox to an instance of FontSetting.
So each item in the ComboBox actually display a string representing a certain color now, what I want to do is set an item's Foreground color to that color its content indicates, like this:
Can anyone help? Thanks.
UPDATED:
Since most of the solutions have a converter which converts string to Brush and actually I already have it, now I want to put mine here, as I binded a TextBox's Foreground to FontSetting's FontColor property, so that when you change the ComboBox, the color of that TextBox changes accordingly.
Here is my converter class, and it works fine by now:
class StringToBrushConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
BrushConverter conv = new BrushConverter();
SolidColorBrush brush = conv.ConvertFromString("Lavender") as SolidColorBrush;
if (null != value)
{
brush = conv.ConvertFromString(value.ToString()) as SolidColorBrush;
}
return brush;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
When I click the ComboBox to open the dropdown list, I got an exception:
CONCLUSION
Amine's solution works, it's my mistake. I explain briefly now, if you bind a ComboBox to System.Windows.Media.Colors like what I am doing, when the item is rendered, the Convert() method of the converter class (which you assign to the binding) is executed, and actually the value passed to Convert() as its first parameter is a Syetem.Windows.Media.Color instance. I made mistake coz I thought it was of string type.
Therefore, in my case I need two converter classes, one converting string to Brush, and the other one converting Color to Brush. So I will keep my own StringToBrush converter and add Amine's ColorToBrush converter.
However, I simplified Amine's implementation a bit:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
BrushConverter conv = new BrushConverter();
SolidColorBrush brush = SolidColorBrush)conv.ConvertFromString(FontSetting.DEFAULT_FONT_COLOR);
if (null != value)
{
PropertyInfo pi = value as PropertyInfo;
if (null != pi)
{
brush = conv.ConvertFromString(pi.Name) as SolidColorBrush;
}
}
return brush;
}
Moreover, Joe's input is also valuable, put all them together, I can keep the items' color consistent, which is perfect.
You can set Style of ComboBoxItem as bellow :
<ComboBox Grid.Column="1" Grid.Row="1" Height="22" Width="240" x:Name="CB"
VerticalAlignment="Center" HorizontalAlignment="Left"
ItemsSource="{Binding Source={StaticResource colorPropertiesOdp}}"
DisplayMemberPath="Name"
SelectedValuePath="Name">
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="Foreground" Value="{Binding Converter={StaticResource converter}}"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
By using this converter:
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
object obj = ((System.Reflection.PropertyInfo)value).GetValue(this,null);
return (SolidColorBrush)new BrushConverter().ConvertFromString(obj.ToString());
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return value;
}
}
Two ways, use a value converter or an intermediate property. The easiest is probably an intermediate property as you are using well structured bindings already for your SelectedItem (but value converters are fun too!).
SelectedValue is bound to FontColor, so in your setter set another value:
public string FontColor
{
get
{
return _fontColor;
}
set
{
_fontColor = value;
ForegroundColorToDisplay = GetBrushFromColorString(value);
OnPropertyChanged("FontColor");
}
}
public Brush _foregroundColorToDisplay
public Brush ForegroundColorToDisplay
{
get
{
return _foregroundColorToDisplay;
}
set
{
_foregroundColorToDisplay= value;
OnPropertyChanged("ForegroundColorToDisplay");
}
}
or, if you don't want to store it:
public string FontColor
{
get
{
return _fontColor;
}
set
{
_fontColor = value;
//note it fires two changed events!
OnPropertyChanged("ForegroundColorToDisplay");
OnPropertyChanged("FontColor");
}
}
public Brush ForegroundColorToDisplay
{
get
{
return GetBrushFromColorString(value);;
}
}
You can bind to this new property in your xaml:
<ComboBox Grid.Column="1" Grid.Row="1" Height="22" Width="240"
VerticalAlignment="Center" HorizontalAlignment="Left"
ItemsSource="{Binding Source={StaticResource colorPropertiesOdp}}"
SelectedValue="{Binding FontColor, Mode=TwoWay}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
Foreground="{Binding ForegroundColorToDisplay, Mode=OneWay}"/>
If you are interested, a value converter would work like this:
Create a class in your code behind (or elsewhere if it's going to be used a lot) that implements IValueConverter, takes the string and returns a Brush:
public class StringToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return GetBrushFromString(value as string)
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
Throw new SomeException();
}
}
and use it in your binding in xaml to convert the selectedItem binding to Foreground brush:
<Window.Resources>
<local:StringToBrushConverter x:Key="converter" />
</Window.Resources>
...
<ComboBox Grid.Column="1" Grid.Row="1" Height="22" Width="240"
VerticalAlignment="Center" HorizontalAlignment="Left"
ItemsSource="{Binding Source={StaticResource colorPropertiesOdp}}"
SelectedValue="{Binding FontColor, Mode=TwoWay}"
DisplayMemberPath="Name"
SelectedValuePath="Name"
Foreground="{Binding FontColor, Mode=OneWay, Converter={StaticResource converter}}"/>
I have a wpf application ,in which I have a tabcontrol ,I set its ItemTemplate from an external resource dictionary,in that template I have an Image Control which I bind to a string Property 'ImagePath' in my ViewModel and using a converter I convert 'ImagePath' into new bitmapImage .I created my converter class instance in the external resource disctinary. I merged the external dictionary in my App.xaml
Here is my External Resource Dictionary:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helpers="clr-namespace:RH_Maize.Helper">
<helpers:ImageSourceConverter x:Key="ImageSourceConverter" />
<DataTemplate x:Key="ClosableTabItemTemplate">
<StackPanel Width="155"
Orientation="Horizontal"
Height="35">
<Image Height="25"
Width="30"
Source="{Binding Path=ImagePath,Converter={ StaticResource ImageSourceConverter}}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding DisplayName}"
Width="100" Height="27" VerticalAlignment="Bottom" FontSize="15" Margin="3,0,0,0"/>
<Button Command="{Binding CloseCommand}"
Content="x" />
</StackPanel>
</DataTemplate>
Here is my Converter class :
public class ImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (targetType == typeof(ImageSource))
{
if (value is string)
{
string str = (string)value;
return new BitmapImage(new Uri(str, UriKind.RelativeOrAbsolute));
}
else if (value is Uri)
{
Uri uri = (Uri)value;
return new BitmapImage(uri);
}
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
My ViewModel Property is :
private string _ImagePath;
public string ImagePath
{
get
{
return _ImagePath;
}
set
{
_ImagePath = value;
RaisePropertyChanged(() => ImagePath);
}
}
My problem is that the converter classes convert method is not invoking at all .Whats wrong with my code ?
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
i am binding imagebrush source to my datatemplate in xaml.
the datatemplate is--->
<DataTemplate x:Key="UserGridListTemplate">
<Grid Height="140" Width="155">
<Grid.Background>
<ImageBrush ImageSource="{Binding imagePath}"/>
</Grid.Background>
</Grid>
</DataTemplate>
and xaml--->
<ListBoxItem ContentTemplate="{StaticResource UserGridListTemplate}" >
<local:MultiLineItem ImagePath="/ShareItMobileApp;component/Images/facebook-avatar(1).png"/>
</ListBoxItem>
but an exception occuring
AG_E_PARSER_BAD_PROPERTY_VALUE [Line: 3 Position: 33]
can anyone help me about this ???
The reason you're getting that error is because ImageBrush does not derive from FrameworkElement which means you can't bind the data directly like that. You can create a converter that will convert your imagePath into an ImageBrush and set that ImageBrush as a background to the grid's Background property.
First you need to create a converter to convert your path string into an ImageBrush.
public class ImagePathConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter)
{
if(value == null) return null;
Uri uri = new Uri(value.ToString(), UriKind.RelativeOrAbsolute);
ImageBrush ib = new ImageBrush();
ib.ImageSource = new BitmapImage(uri);
return ib;
}
public object ConvertBack(object value, Type targetType, object parameter)
{
throw new NotImplementedException();
}
}
You can then use that converter on your Grid's background binding (after you've added it as a resource with the key ImgPathConverter).
<DataTemplate x:Key="UserGridListTemplate">
<Grid Height="140" Width="155"
Background={Binding imagePath, Converter={StaticResource ImgPathConverter}}/>
</DataTemplate>