Implementing IValueConverter to convert string to image - c#

I am currently trying to displaying images in my Windows 8 application. I have a method which populates a property of type List<string> with a number of paths to images. I wish to display these images on screen.
Thus, I have implemented a converter to go from string to image. However, I get the errors :
The name "StringToImageConverter" does not exist in the namespace
"using:TestApp.Converters".
'TestApp.Converters.StringToImageConverter' does not implement
interface member
'Windows.UI.Xaml.Data.IValueConverter.ConvertBack(object,
System.Type, object, string)'
'TestApp.Converters.StringToImageConverter' does not implement
interface member
'Windows.UI.Xaml.Data.IValueConverter.Convert(object, System.Type,
object, string)'
Here is the code from my Converter :
namespace TestApp.Converters
{
public sealed class StringToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
try
{
return new BitmapImage(new Uri((string)value));
}
catch
{
return new BitmapImage();
}
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
And from my XAML file :
<common:LayoutAwarePage
...
xmlns:converters="using:TestApp.Converters"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Page.Resources>
<converters:StringToImageConverter x:Key="StringToImageConverter"> </converters:StringToImageConverter>
</Page.Resources>
...
<ItemsControl ItemsSource="{Binding Path=test}" Grid.Column="1" Grid.Row="3" Grid.ColumnSpan="4"
HorizontalContentAlignment="Stretch">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Converter={StaticResource StringToImageConverter}}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
...
Should this work for displaying my images in the Windows 8 application? The List<string> of image paths is called test and is in the code behind of the xaml file.
Thanks very much for any and all help with this :)

Apparently there are two types of IValueConverters:
Windows.UI.Xaml.Data.IValueConverter
System.Windows.Data.IValueConverter
It sounds like your framework is expecting the former, while you're implementing the latter.
You probably also need to change this:
xmlns:converters="using:TestApp.Converters"
to this:
xmlns:converters="clr-namespace:TestApp.Converters"

Windows.UI.Xaml.Data.IValueConverter expects the last parameter to be a string, not a CultureInfo

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System.Collections;assembly=mscorlib"
xmlns:p="clr-namespace:System;assembly=mscorlib"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Entities="clr-namespace:Entities;assembly=Entities"
mc:Ignorable="d"
x:Name="XXXXX"
x:Class="AAAA.XXXXX" Title="Seciones" Height="644.305" Width="909.579"
xmlns:c="clr-namespace:AAAA">
<Window.Resources>
<c:StringToImageConverter x:Key="stringToImageConverter"/>
</Window.Resources>
.....
</Window>

Related

Accessing UserControl Resource Dictionary from code

I' am trying to read/load a UserControl Resources from my Home.xaml to a ResourceDictionary object so I can dynamicly display it inside content control and can't manage to find a solution.
I dont want to read it from my App.xaml, just the Home.xaml.
In my View folder I have Home.xaml:
<UserControl.Resources>
<converters:CheckBoxConverter x:Key="CheckBoxConv"></converters:CheckBoxConverter>
<DataTemplate x:Key="Punomoc">
<CheckBox Margin="10" Content="Izradi punomoć"
IsChecked="{Binding UnosIOS.Punomoc}">
</CheckBox>
</DataTemplate>
<DataTemplate x:Key="Naknada">
<CheckBox Margin="10,0" Content="Naplata naknade"
IsChecked="{Binding UnosIOS.NaplataNaknade}">
</CheckBox>
</DataTemplate>
</UserControl.Resources>
<Grid>
...
```
...
```
In my ConvertersFolder I have:
public class CheckBoxConverter : IValueConverter
{
private static readonly ResourceDictionary ControlResourceDictionary;
static CheckBoxConverter()
{
ControlResourceDictionary = new ResourceDictionary
{
Source = new Uri("pack://application:,,,/View/Home.xaml", UriKind.Absolute)
};
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DataTemplate dataTemplate =ControlResourceDictionary["Punomoc"] as DataTemplate;
return dataTemplate;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
But its returning error:
''The invocation of the constructor on type 'IzdavanjeIOS.Converters.CheckBoxConverter' that matches the specified binding constraints threw an exception.' Line number '23' and line position '10'.'
Also tried with URI string : MyAppName/View/Home.xaml
I have setup MVVM and dont want to access resources from code-behind unless its the only choice, it seems to me that it should be possible like above, but maybe I am giving the wrong URI?

How to bind TextBlock to self-made FrameworkElement property?

I have a 'GameControl : FrameworkElement'. I have it in the xaml like this:
<local:GameControl x:Name="control"/>
This GameControl has a property that is an own class:
public Gem selectedGem {get; set;}
Now, I want to write this Gem's information into a TextBlock, so that the player will see its properties.
How do I bind my own FrameworkElement's properties to the MainWindow's elements?
--
Full xaml:
<Window x:Class="GemTowerDefense.MainWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:GemTowerDefense"
mc:Ignorable="d"
Title="Gem Tower Defense" Height="670" Width="800"
ResizeMode="NoResize">
<Grid>
<Border Background="Gray" Height="600" Width="600" Margin="3,26,189,3">
<local:GameControl x:Name="control"/>
</Border>
<Border Background="LightSlateGray" HorizontalAlignment="Left" VerticalAlignment="Top" Height="285" Margin="608,181,0,0" Width="170">
<TextBlock x:Name="tbInfo" Text="Gem information">
</TextBlock>
</Border>
</Grid>
</Window>
(Instead of Text=Gem Information, I want the binding to the control's selectedGem, or to one of its string type property)
You make your property a dependency property and when binding that property to the TextBlock.Text, use a converter. Search Stackoverflow to find billion examples on both topics. The binding would look something like this:
Text="{Binding ElementName=control, Mode=OneWay, Path=selectedGem, Converter={local:ExampleConverter}}"
I find it easiest to create converter in code-behind:
public class ExampleConverter : MarkupExtension, IValueConverter
{
public ExampleConverter()
{
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if(value != null && value is Gem)
return (value as Gem).GemAsText();
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
#endregion
}

Resource could not be resolved

I got a error "The resource "ComponentTypeToStringConverter could not be resolved" Can someone tell me what am I doing wrong?
I've got this combo box:
<ComboBox SelectedItem="{Binding PcComponent.ComponentTypeName}" Grid.Column="1" Grid.Row="2" Grid.ColumnSpan="2">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource ComponentTypeToStringConverter}}"/> <!-- HERE I got a error The resource "ComponentTypeToStringConverter could not be resolved -->
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Resource:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:PcConfigurator.Converters">
<c:ComponentTypeToStringConverter x:Key="ComponentTypeToStringConverter"/>
</ResourceDictionary>
Converter (namespace PcConfigurator.Converters):
public class ComponentTypeToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is ComponentType)) { return null; }
ComponentType type = (ComponentType)value;
switch (type)
{
//Do something
}
throw new InvalidOperationException("Enum value is unknown");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
In design time. Your resources are not yet compiled and the current XAML file that you have where it has the ComboBox can't see the ResourceDictionary.
Assuming your resources is defined in App.xaml then you should have no problems with it when you run it in runtime as it'll be able to find the key.
If you want to get rid of the error in design time then what you can do is on your XAML file where the ComboBox lives, you can add the ResourceDictioanry so that it'll be able to find it.
Assuming this is a Window and you have ResourceDictionary that is not defined in the App.xaml but as a separate file
<Window.Resources>
<ResourceDictionary Source=""/>
</Window.Resources>

Localizing dialogs in MVVM: is it good to reference the resources from the ViewModel?

I've gotten to the point where I need to add localization to my WPF MVVM application (I use Caliburn.Micro + Autofac).
I did some research, and I've found many different ways to accomplish it, but none provide a solution to localize the text of a dialog.
As dialogs I use a DialogViewModel that Caption and Message string properties, and I show it in a DialogView using CM's WindowManager.
What I have atm is something like
this.windowManager.ShowDialog(new DialogViewModel("Hello!", "Hello everybody!!"))
but also things like
this.windowManager.ShowDialog(new DialogViewModel("Hello!", "Hello " + this.Name + "!!"))
I thought I could use a resource string like "Hello {0}!!" and use it this way
this.windowManager.ShowDialog(new DialogViewModel("Hello!", string.Format(languageResources.HelloName, this.Name)))
Is it good to do reference the localization resources from the ViewModel layer?
Resources is the data that uses a View, and my opinion is that is not advisable from the ViewModel refer to resources. On the other hand, if it is a class (may be static) that stores a specific strings, and knows nothing of the View it will be some abstraction that can be in the ViewModel. In any case, you should try to work with the resources on the side View using techniques that I will give, or any other.
Using x:Static Member
In WPF, it is possible to bind static data from a class like this:
<x:Static Member="prefix : typeName . staticMemberName" .../>
Below is an example where the format string is in a class, the format used to display the date and time.
XAML
xmlns:local="clr-namespace:YourNameSpace"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
<Grid>
<TextBlock Text="{Binding Source={x:Static sys:DateTime.Now}, StringFormat={x:Static Member=local:StringFormats.DateFormat}}"
HorizontalAlignment="Right" />
<TextBlock Text="{Binding Source={x:Static sys:DateTime.Now}, StringFormat={x:Static Member=local:StringFormats.Time}}" />
</Grid>
Code behind
public class StringFormats
{
public static string DateFormat = "Date: {0:dddd}";
public static string Time = "Time: {0:HH:mm}";
}
In this case, the StringFormats class be regarded as a resource, although actually it is a normal class. For more information, please see x:Static Markup Extension on MSDN.
Using Converter
If you have the resources stored in Application.Current.Resources and need to add some logic, in this case, you can use the converter. This example is taken from here:
XAML
<Button Content="{Binding ResourceKey, Converter={StaticResource resourceConverter}}" />
Code behind
public class StaticResourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var resourceKey = (string)value;
// Here you can add logic
return Application.Current.Resources[resourceKey];
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new Exception("The method or operation is not implemented.");
}
}
Note: In the converter, it is better not to use heavy logic, because it can affect the performance. For more complex logic, see below.
Attached Behavior
Attached behavior should be used for complex actions with visual elements when no x:Static Member and converter is not helped. Attached behavior is very powerful and convenient solution that fully satisfies the MVVM pattern, which can also be used in the Blend (with a pre-defined interface). You can define an attached property in which property handler to access elements and to its resources.
Examples of implementation attached behaviors, see below:
Set focus to a usercontrol when it is made visible
Animated (Smooth) scrolling on ScrollViewer
Setting WindowStartupLocation from ResourceDictionary throws XamlParseException
Example with converter
App.xaml
Here I store strings for each culture.
<Application x:Class="MultiLangConverterHelp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
StartupUri="MainWindow.xaml">
<Application.Resources>
<sys:String x:Key="HelloStringEN">Hello in english!</sys:String>
<sys:String x:Key="HelloStringRU">Привет на русском!</sys:String>
</Application.Resources>
</Application>
MainWindow.xaml
The input is the current culture, which can be obtained within the converter, for simplicity of an example I did so.
<Window x:Class="MultiLangConverterHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MultiLangConverterHelp"
WindowStartupLocation="CenterScreen"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:StaticResourceConverter x:Key="converter" />
<local:TestViewModel x:Key="viewModel" />
</Window.Resources>
<Grid DataContext="{StaticResource viewModel}">
<TextBlock Text="{Binding Path=CurrentCulture, Converter={StaticResource converter}}" />
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class StaticResourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var currentCulture = (string)value;
if (currentCulture.Equals("EN-en"))
{
return Application.Current.Resources["HelloStringEN"];
}
else if (currentCulture.Equals("RU-ru"))
{
return Application.Current.Resources["HelloStringRU"];
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
public class TestViewModel : NotificationObject
{
private string _currentCulture = "EN-en";
public string CurrentCulture
{
get
{
return _currentCulture;
}
set
{
_currentCulture = value;
NotifyPropertyChanged("CurrentCulture");
}
}
}
Also, I advise you to learn more simple ways, which is already in the WPF technology:
WPF Localization for Dummies
WPF Globalization and Localization Overview

C# / WPF - DesignData - Binding to DesignData Collection Properties

I like design time data, especially when creating small widgets. For this very simple use case I'm having trouble binding to the properties of a design-time list which I have created in xaml.
Please find my ViewModel, View and SampleData below;
ViewModel
internal class SummaryViewModel : ViewModelBase
{
public string Title { get; set; }
public IList<Person> PersonList { get; set; }
internal SummaryViewModel()
{
PersonList = new List<Person>();
}
}
Sample Data
<ViewModel:SummaryViewModel xmlns:ViewModel="ViewModel" Title="Test Title">
<ViewModel:SummaryViewModel.Connections>
<ViewModel:ConnectionViewModel Id="0" />
<ViewModel:ConnectionViewModel Id="1" />
</ViewModel:SummaryViewModel.Connections>
</ViewModel:SummaryViewModel>
View
<StackPanel x:Class="View.SummaryView"
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"
mc:Ignorable="d"
d:DesignHeight="100"
d:DesignWidth="100"
d:DataContext="{d:DesignData Source=/DesignData/SampleSummaryViewModel.xaml}"
Orientation="Vertical"
Background="LightGreen">
<!-- This Works -->
<Label FontSize="10" FontWeight="Bold" Content="{Binding Title}" />
<!-- This Works -->
<ListBox ItemsSource="{Binding PersonList}" />
<!-- This DOESN'T work -->
<Label FontSize="8" Content="{Binding PersonList, Path=Count}"/>
</StackPanel>
How would you configure SampleData such that you could bind to the Count of a list specified therein?
I have tried setting the resource type as both DesignData and DesignDataWithDesignTimeCreatableTypes with no luck.
It should be:
<Label FontSize="8" Content="{Binding Path=PersonList.Count}"/>
Also Mårten is correct, you should use an ObservableCollection instead.
HTH
CityView, just as a side note: to debug DataBinding I usually use an empty converter which only returns the value it was given. I put a breakpoint in there and that way I can see what exactly is going back and forth.
public class BindTestConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
}
Combined with that and what the Output window tells me usually leads me to a solution to the problem at hand.
It should work, but become a one-time binding since your list does not implement INotifyPropertyChanged and therefore the binding is not updated when Count changes.
Try using an ObservableCollection<Person> instead.

Categories

Resources