datatemplate binding image brush source - c#

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>

Related

WPF - Bind ComboBox Item Foreground to Its Value

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}}"/>

Image Source not refreshing after Editing Binding Source

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?

set Image source from a resource dictionary

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 ?

WPF binding: Set Listbox Item text color based on property

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

How bind TabControl?

xaml
<controls:TabControl x:Name="tabControlRoom" Grid.Row="1" Grid.Column="1" d:LayoutOverrides="Width, Height" ItemsSource="{Binding}" >
<controls:TabControl.ItemTemplate>
<DataTemplate>
<controls:TabItem Header="{Binding name}">
<StackPanel Margin="10" Orientation="Horizontal">
</StackPanel>
</controls:TabItem>
</DataTemplate>
</controls:TabControl.ItemTemplate>
</controls:TabControl>
and code
m_roomContext.Load(m_roomContext.GetRoomQuery());
tabControlRoom.DataContext = m_roomContext.Rooms;
when I open this page, then there is all the elements, but a second later I see only a white screen
error:
load operation failed for query
'GetRoom'. Unable to cast object of
type 'Web.Room' to type
'System.Windows.Controls.TabItem'/'
Create converter
public class SourceToTabItemsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
var source = (IEnumerable)value;
if (source != null)
{
var controlTemplate = (ControlTemplate)parameter;
var tabItems = new List<TabItem>();
foreach (object item in source)
{
PropertyInfo[] propertyInfos = item.GetType().GetProperties();
//тут мы выбираем, то поле которое будет Header. Вы должны сами вводить это значение.
var propertyInfo = propertyInfos.First(x => x.Name == "name");
string headerText = null;
if (propertyInfo != null)
{
object propValue = propertyInfo.GetValue(item, null);
headerText = (propValue ?? string.Empty).ToString();
}
var tabItem = new TabItem
{
DataContext = item,
Header = headerText,
Content =
controlTemplate == null
? item
: new ContentControl { Template = controlTemplate }
};
tabItems.Add(tabItem);
}
return tabItems;
}
return null;
}
catch (Exception)
{
return null;
}
}
/// <summary>
/// ConvertBack method is not supported
/// </summary>
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("ConvertBack method is not supported");
}
Create ControlTemplate:
<ControlTemplate x:Key="MyTabItemContentTemplate">
<StackPanel>
<TextBlock Text="{Binding Path=name}" />
</StackPanel>
</ControlTemplate>
And binding convert, controltemplate
<controls:TabControl x:Name="tabControl"
ItemsSource="{Binding ElementName=tabControl,
Path=DataContext,
Converter={StaticResource ConverterCollectionToTabItems},
ConverterParameter={StaticResource MyTabItemContentTemplate}}">
</controls:TabControl>
taken from the blog binding-tabcontrol
When binding the TabControl there are two things you need to accomplish, one is the header content for the TabItem the other is the content for the selected TabItem, which is generally another user control.
The way have I've solved this in the past is to bind ItemsSource of the TabControl to a collection of view models, and to provide two data templates, one to supply the header content for the TabItem, an the other to supply the content for the selected TabItem, which maps to a view.
<Window.Resources>
<DataTemplate x:Key="ItemTemplate">
<TextBlock Text="{Binding Title}" />
</DataTemplate>
<DataTemplate x:Key="ContentTemplate">
<local:SampleView />
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl
ItemsSource="{Binding SampleViewModels}"
ItemTemplate="{StaticResource ItemTemplate}"
ContentTemplate="{StaticResource ContentTemplate}"
SelectedIndex="0"
/>
</Grid>

Categories

Resources