i'm trying to apply a converter for my image source binding. here's my xaml:
<Window.Resources>
<DataTemplate x:Key="listBoxTemplate">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<ImageConverter x:Key="MyImageConverter" />
</StackPanel.Resources>
<Image Source="{Binding Path=thumb, StringFormat=/WpfTest;component/Images/{0}, Converter={StaticResource MyImageConverter}}" Height="100" Width="130" Margin="5"></Image>
<StackPanel Orientation="Vertical" Width="247">
<TextBlock Text="{Binding recipeName}" Height="60" Padding="15" FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Center"></TextBlock>
<TextBlock Text="{Binding cuisine}" Height="60" Padding="15" FontSize="16" HorizontalAlignment="Stretch" VerticalAlignment="Center"></TextBlock>
</StackPanel>
</StackPanel>
</DataTemplate>
</Window.Resources>
and here's my imageConverter class:
using System;
using System.Windows.Data;
using System.Globalization;
using System.Windows.Media.Imaging;
public class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string path = (string)value;
try
{
//ABSOLUTE
if (path.Length > 0 && path[0] == System.IO.Path.DirectorySeparatorChar
|| path.Length > 1 && path[1] == System.IO.Path.VolumeSeparatorChar)
return new BitmapImage(new Uri(path));
//RELATIVE
return new BitmapImage(new Uri(System.IO.Directory.GetCurrentDirectory() + System.IO.Path.DirectorySeparatorChar + path));
}
catch (Exception)
{
return new BitmapImage();
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
but when i tried running the apps, it returns "the type imageconverter was not found" and VS highlight the part
<ImageConverter x:Key="MyImageConverter" />
in the xaml above. How do I fix it? (Btw I got the imageconverter code from Wpf - relative image source path )
You need to add its namespace like this:
<ns:ImageConverter x:Key="MyImageConverter"/>
And make sure you added the namespace higher up like this:
<DataTemplate xmlns:ns="....">
The actual namespace depends on you project but code completion will help you.
Related
I am total beginner trying to learn WPF/C#, Basically I want following:
Show canvases in multiple places (usualy datagrid columns based on value)
To use Convertor that will fetch right canvas (based on value and parameter) and return it as imagesource*
I don't want to convert canvas to imagefile and return filepath
Understand that this is how i imagined to make it, if you have a better solution that doesn't include having image files in folder and using paths it will help me
I have the following XAML: (File: MyApp.Views.MainView.xaml)
<Window.Resources>
<conv:ValueToImageConvertor x:Key="_ValueToImageConvertor" />
</Window.Resources>
<DataGridTemplateColumn Header="Icon">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<Image Name="img" Source="{Binding SomeValue,Converter={StaticResource _ValueToImageConvertor} ConverterParameter=SomeParameter}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Here is the Resource Dictionary where i store my canvases: (File: MyApp.Resources.ImagesDictionary.xaml)
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyApp.Resources">
<Viewbox x:Key="i_img1" Width="24" Height="24">
<Canvas Width="24" Height="24">
<Path Data="XXXXXXX" Fill="Black" />
</Canvas>
</Viewbox>
<Viewbox x:Key="i_img2" Width="24" Height="24">
<Canvas Width="24" Height="24">
<Path Data="YYYYY" Fill="Black" />
</Canvas>
</Viewbox>
</ResourceDictionary>
And i want to make a converter:(File: MyApp.Converters.ValueToImageConverter.cs)
public class ValueToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//Based on value and parameter get specific canvas and display it
//get canvas and convert it as image source without creating file
}
}
As i mentioned above, maybe this is a totally bad approach. I am newbie who is trying to learn. Please help me. Thank you.
Ok folks, i did it. This is how:
1) I have resource dictionary file ("Resources/ImagesDictionary.xaml")
<Viewbox x:Key="i_male" x:Shared="False">
<Canvas Width="24" Height="24">
<Path Data="XXXXXX" Fill="Black" />
</Canvas>
</Viewbox>
<Viewbox x:Key="i_female" x:Shared="False">
<Canvas Width="24" Height="24">
<Path Data="YYYYY" Fill="Black" />
</Canvas>
</Viewbox>
2) My main xaml datagrid column for image in file ("Views/wndUsers.xaml")
<Window.Resources>
<conv:ValueToImageConverter x:Key="_ValueToImageConverter" />
</Window.Resources>
<DataGridTemplateColumn Header="Sex" Width="SizeToCells" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate >
<ContentControl Content="{Binding Sex, Converter={StaticResource
_ValueToImageConverter}, ConverterParameter=0}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
3) Converter ValueToImageConverter file ("Converters/ValueToImageConverter")
public class ValueToImageConverter : IValueConverter
{
private ResourceDictionary _resDictionary = new ResourceDictionary();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
_resDictionary.Source = new Uri("Resources/ImagesDictionary.xaml", UriKind.Relative);
switch (parameter)
{
case "0":
return (bool)value == true ? _resDictionary["i_female"] : _resDictionary["i_male"];
default:
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
Now you can use this converter anywhere where u need an image based on value and parameter
refers to implementing a multilanguage interface now I have a problem. I have a grid where its ItemSource it's a Dictionary<string, string>: I can't give the key value as parameter of the markup extension because I have the following exception
A 'Binding' cannot be set on the 'Value1' property of type 'TranslateMarkupExtension'.
A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
This is the xaml where I use the markup extension:
<ItemsControl ItemsSource="{Binding MyDictionary}" Grid.Row="0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Content="{TranslateMarkup Value1 = {Binding Path = Key}}" Grid.Column="0" />
<TextBox Tag="{Binding Key, Mode=OneWay}" Text="{Binding Value, Mode=OneWay}" Width="200" Height="46" VerticalContentAlignment="Center" Grid.Column="1" LostFocus="TextBox_OnLostFocus" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I can't find any workaround..I need the dictionary as item source because the label will show the key and the textbox the corresponding value..I tried also replacing the dictionary with a list of object but the problem still remains.
Does anyone have a good hint? Thanks in advance.
As suggested by Ed Plunkett, the solution is the ValueConverter.
So the label is know this:
<Label Content="{Binding Key, Converter={StaticResource MultiLangConverter}}" Grid.Column="0" />
where my ValueConverter is the following:
public class StringToMultiLangConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var stringValue = (string) value;
if (string.IsNullOrEmpty(stringValue))
return string.Empty;
string multiLang = LangTranslator.GetString(stringValue);
return multiLang ?? value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
Thanks for the help!
I have two textboxes bound to a slider. I want the second textbox to be 1.2 time the value of the slide.
<Slider Maximum="500" Minimum="25" TickFrequency="5" IsSnapToTickEnabled="True" Name="slCellHeight" />
<TextBox Text="{Binding ElementName=slCellHeight, Path=Value, UpdateSourceTrigger=PropertyChanged}" Width="40" Name="txtCellHeight" />
<TextBox Text="{Binding ElementName=slCellHeight, Path=Value, UpdateSourceTrigger=PropertyChanged}" Width="40" Name="txtCellWidth" />
That is, when the slider shows 100, the first textbox(txtCellHeight) should show 100. This is working fine. I want to the second one to be 120.
I tried the calBinding but no success. Please suggest some good ways to do that.
Use a converter.
XAML:
<Window.Resources>
<local:MultiplyConverter x:Key="MultiplyConverter" />
</Window.Resources>
...
<TextBox Text="{Binding ElementName=slCellHeight, Path=Value,
UpdateSourceTrigger=PropertyChanged, Converter={StaticResource
MultiplyConverter}, ConverterParameter=1.2 }" Width="40" Name="txtCellWidth" />
Class MultiplyConverter:
class MultiplyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double result;
double.TryParse(parameter.ToString(), out result);
double mult = (double)value * result;
return mult;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I've done it on the fly, so maybe it will need some fixes to compile.
How can I transfer the Source attribute from a button template to an Image inside that template ?
This is how my XAML looks like:
<Page x:Class="TallShip.MainGallery"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TallShip"
mc:Ignorable="d"
d:DesignHeight="1080" d:DesignWidth="1920"
Title="MainGallery">
<Grid>
<ScrollViewer Height="958" HorizontalAlignment="Left" Margin="685,87,0,0" Name="GalleryRightScroller" VerticalAlignment="Top" Width="1159" PanningMode="VerticalOnly" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="GalleryObject">
<StackPanel Height="Auto" HorizontalAlignment="Left" Margin="{TemplateBinding Margin}" VerticalAlignment="Top" Width="500">
<Image Height="200" Stretch="None" Source="{TemplateBinding local:SourceHolder.Source}" Width="200" />
<Label Content="{TemplateBinding local:SourceHolder.Source}" Height="28" Name="label1" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" />
</StackPanel>
</ControlTemplate>
</Grid.Resources>
<Button Template="{StaticResource GalleryObject}" local:SourceHolder.Source="/TallShip;component/media/91gx2EQ.jpg" Name="object1" Margin="43,21,0,0"/>
<Button Template="{StaticResource GalleryObject}" local:SourceHolder.Source="/TallShip;component/media/91gx2EQ.jpg" Name="object2" Margin="43,280,0,0"/>
</Grid>
</ScrollViewer>
</Grid>
And this is the custom control class I've created to hold the Source property:
namespace TallShip {
public static class SourceHolder
{
public static readonly DependencyProperty SourceProperty = DependencyProperty.RegisterAttached("Source",
typeof(string), typeof(SourceHolder), new FrameworkPropertyMetadata(null));
public static string GetSource(UIElement element)
{
if (element == null)
throw new ArgumentNullException("element");
return (string)element.GetValue(SourceProperty);
}
public static void SetSource(UIElement element, string value)
{
if (element == null)
throw new ArgumentNullException("element");
element.SetValue(SourceProperty, value);
}
}
}
Currently, the label correctly displays the passed source, but the image does not work...
If I use the same source on an image outside of the button template, the image works just fine.
Option 1:
<Image Height="200" Stretch="None" DataContext="{TemplateBinding local:SourceHolder.Source}" Width="200" Source="{Binding}"></Image>
Option 2:
If that does not work, Use other alternative of using ValueConverter in Image binding that converts uri to Image
public class UriToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
if (value is string)
value = new Uri((string)value, UriKind.RelativeOrAbsolute);
if (value is Uri)
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = (Uri)value;
bi.EndInit();
return bi;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
<Window.Resources>
<local:UriToImageConverter x:Key="uriToImageConverter"></local:UriToImageConverter>
</Window.Resources>
<Image Height="200" Stretch="None" DataContext="{TemplateBinding local:SourceHolder.Source}" Width="200" Source="{Binding Converter={StaticResource ResourceKey=uriToImageConverter}}"></Image>
Morning Guys,
I have a few ComboBoxes bound to List of TimeSpan. I am formatting the TimeSpans using IValueConverter and ItemTemplate. I was wondering if there were an easier way to format the TimeSpans. Here's what I'm currently doing.
public class TimeSpanConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return string.Empty;
TimeSpan t = TimeSpan.MinValue;
TimeSpan.TryParse(value.ToString(), out t);
return "{0:00}:{1:00}".F(t.Hours,t.Minutes);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return TimeSpan.Parse(value.ToString());
}
#endregion
}
<Canvas>
<Canvas.Resources>
<bc:TimeSpanConverter x:Key="ts" />
<DataTemplate x:Key="TimeSpanTemplate">
<TextBlock Text="{Binding ., Converter={StaticResource ts}}" />
</DataTemplate>
</Canvas.Resources>
<TextBlock Canvas.Left="6"
Canvas.Top="6"
Height="21"
Name="textBlock4"
Text="Begin"
Width="40" />
<TextBlock Canvas.Left="81"
Canvas.Top="6"
Height="21"
Name="textBlock5"
Text="End"
Width="40" />
<ComboBox Canvas.Left="7"
Canvas.Top="25"
Height="23"
Name="TimeBeginCombo"
ItemTemplate="{StaticResource TimeSpanTemplate}"
SelectedItem="{Binding TimeBegin}"
Width="68" />
<ComboBox Canvas.Left="81"
Canvas.Top="25"
Height="23"
Name="TimeEndCombo"
ItemTemplate="{StaticResource TimeSpanTemplate}"
SelectedItem="{Binding TimeEnd}"
Width="68" />
</Canvas>
</GroupBox>
Is what you're binding to of type TimeSpan? If so, then the converter can be much simpler
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is TimeSpan))
return string.Empty;
TimeSpan t = (TimeSpan)value;
return "{0:00}:{1:00}".F(t.Hours,t.Minutes);
}
And also, a general remark - are you sure you need to layout your UI on a Canvas and using absolute coordinates? :)