WPF: Can't instantiate class in Window.Resources - c#

I'm doing this WPF tutorial and for some reason I get an error when adding a custom SlidersToColorConverter class to resources.
Someone on StackOverflow was doing it exact same way.
MainWindow.xaml:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:SlidersToColorConverter x:Key="whyareyounotworking"/>
</Window.Resources>
</Window>
SlidersToColorConverter.cs:
namespace WpfApplication2
{
class SlidersToColorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double red = (double)values[0];
double green = (double)values[1];
double blue = (double)values[2];
return new SolidColorBrush(Color.FromArgb(255, (byte)red, (byte)green, (byte)blue));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Error List:
The name "SlidersToColorConverter" does not exist in the namespace "clr-namespace:WpfApplication2". c:\users\mateusz\documents\visual studio 2013\Projects\WpfApplication2\WpfApplication2\MainWindow.xaml 39 9 WpfApplication2

It looks like the class is private (by default). You must change your definition to
public class SlidersToColorConverter : IMultiValueConverter

Related

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
}

InvalidCastException in design time when specify converter as MarkupExtension

I want to implement value converter to specify Point for RenderTransform. That works fine till I just implement IValueConverter interface. I know that I can implement MarkupExtension class to not to declare separated XAML Resource for my converter each time. When I try to implement this, I have
InvalidCastException: Unable to cast object of type 'System.Object' to type 'System.Windows.Data.IValueConverter'.
Converter implementation:
[ValueConversion(typeof(Point), typeof(Transform))]
public class PointToTransformConverter : MarkupExtension, IValueConverter
{
private PointToTransformConverter _instance = null;
public object Convert(
object value,
Type targetType,
object parameter,
CultureInfo culture)
{
var point = (Point)value;
return new TransformGroup
{
Children = new TransformCollection
{
new TranslateTransform(point.X, point.Y)
}
};
}
public object ConvertBack(
object value,
Type targetType,
object parameter,
CultureInfo culture)
{
var transform = value as TransformGroup;
if (transform?.Children.Count > 0)
{
var translateTransform = transform.Children[0] as TranslateTransform;
if (translateTransform != null)
{
return new Point(
translateTransform.X,
translateTransform.Y);
}
}
return null;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return _instance ?? (_instance = new PointToTransformConverter());
}
}
XAML usage:
<local:PathControl x:Class="PathToWiringTube.PathView"
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:PathToWiringTube"
xmlns:view="clr-namespace:PathToWiringTube.View"
xmlns:vm="clr-namespace:PathToWiringTube.VM"
xmlns:crocodile="clr-namespace:Crocodile;assembly=Crocodile"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance vm:PathVm}">
<local:PathControl.Resources>
<crocodile:PointToTransformConverter x:Key="pointToTransformConverter"/>
</local:PathControl.Resources>
<Canvas>
<ItemsControl x:Name="itemsMarkers" ItemsSource="{Binding Markers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<view:SplineDensityMarker Width="5" RenderTransform="{Binding Position, Converter={StaticResource pointToTransformConverter}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</local:PathControl>
What am I doing wrong?
Could you please try the code below and check if the exception is coming?
I have corrected it. The instance should be static and the xaml, you can directly refer to the converter instead of calling it as a static resource. That's the main use of using a MarkupExtension. The code below should work fine. If any issues, please revert.
Converter :
[ValueConversion(typeof(Point), typeof(Transform))]
public class PointToTransformConverter : MarkupExtension, IValueConverter
{
private static PointToTransformConverter _instance = null;
public object Convert(
object value,
Type targetType,
object parameter,
CultureInfo culture)
{
var point = (Point)value;
return new TransformGroup
{
Children = new TransformCollection
{
new TranslateTransform(point.X, point.Y)
}
};
}
public object ConvertBack(
object value,
Type targetType,
object parameter,
CultureInfo culture)
{
var transform = value as TransformGroup;
if (transform?.Children.Count > 0)
{
var translateTransform = transform.Children[0] as TranslateTransform;
if (translateTransform != null)
{
return new Point(
translateTransform.X,
translateTransform.Y);
}
}
return null;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return _instance ?? (_instance = new PointToTransformConverter());
}
}
Xaml :
<local:PathControl x:Class="PathToWiringTube.PathView"
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:PathToWiringTube"
xmlns:view="clr-namespace:PathToWiringTube.View"
xmlns:vm="clr-namespace:PathToWiringTube.VM"
xmlns:crocodile="clr-namespace:Crocodile;assembly=Crocodile"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance vm:PathVm}">
</local:PathControl.Resources>
<Canvas>
<ItemsControl x:Name="itemsMarkers" ItemsSource="{Binding Markers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<view:SplineDensityMarker Width="5" RenderTransform="{Binding Position, Converter={crocodile:PointToTransformConverter}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Canvas>
</local:PathControl>
I've checked my code on another environment and detected that it works. I have done research for Visual Studio version mismatch and found out it (14.0.23107.0 D14REL and 14.0.24720.00 Update1). After installing the latest Visual Studio Update 2 on my old environment everything works fine.

New window as CommandParameter every time

I want a button to show app settings window like this:
<Window.Resources>
<local:SettingsWindow x:Key="SettingsWnd"/>
</Window.Resources>
<Window.DataContext>
<local:MyViewModel/>
</Window.DataContext>
<Button Command="{Binding ShowSettingsCommand}"
CommandParameter="{DynamicResource SettingsWnd}"/>
The ViewModel kinda thing:
class MyViewModel : BindableBase
{
public MyViewModel()
{
ShowSettingsCommand = new DelegateCommand<Window>(
w => w.ShowDialog());
}
public ICommand ShowSettingsCommand
{
get;
private set;
}
}
The problem is that it only works one time because you can't reopen previously closed windows. And apparently, the XAML above does not make new instances to open like that.
Is there a way to pass new window as CommandParameter every time the command is called?
Does this converter solve your problem?
class InstanceFactoryConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var type = value.GetType();
return Activator.CreateInstance(type);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
...
<Window.Resources>
<local:SettingsWindow x:Key="SettingsWnd"/>
<local:InstanceFactoryConverter x:Key="InstanceFactoryConverter"/>
</Window.Resources>
...
<Button Command="{Binding ShowSettingsCommand}"
CommandParameter="{Binding Source={StaticResource SettingsWnd}, Converter={StaticResource InstanceFactoryConverter}}"/>

Shorthand way of specifying strongly typed values in Xaml

Here's what I would like to end up with:
<Grid Visibility={Binding EnablePurchase, Converter={local:ConditionalConverter TrueValue=(Visibility)Visible FalseValue=(Visibility)Collapsed}}/>
Here's currently what I am doing:
<Grid>
<Grid.Visibility>
<Binding Path="EnablePurchase">
<Binding.Converter>
<local:ConditionalConverter>
<local:ConditionalConverter.TrueValue>
<Visibility>Visible</Visibility>
<local:ConditionalConverter.TrueValue>
<local:ConditionalConverter.FalseValue>
<Visibility>Collapsed</Visibility>
<local:ConditionalConverter.FalseValue>
</local:ConditionalConverter>
</Binding.Converter>
</Binding>
</Grid.Visibility>
</Grid>
You can simply create a converter which has properties like this:
public class ValueConverterWithProperties : IValueConverter
{
public int TrueValue { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((int) value == TrueValue)
{
return true;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and then use it like this:
<Window x:Class="Converter.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converter="clr-namespace:Converter"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<converter:ValueConverterWithProperties TrueValue="5" x:Key="converterWithProperties"></converter:ValueConverterWithProperties>
</Window.Resources>
<Grid>
<CheckBox IsChecked="{Binding item, Converter={StaticResource converterWithProperties}}"></CheckBox>
</Grid>
you can also derive from MarkupExtension in your converter for a much nicer usage:
public class ValueConverterWithProperties : MarkupExtension, IValueConverter
{
public int TrueValue { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((int) value == TrueValue)
{
return true;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And then you can set the property directly where you are using the converter allowing you to set different values per converter easily:
<Window x:Class="Converter.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converter="clr-namespace:Converter"
Title="MainWindow" Height="350" Width="525">
<Grid>
<CheckBox IsChecked="{Binding item, Converter={converter:ValueConverterWithProperties TrueValue=5}}"></CheckBox>
<CheckBox IsChecked="{Binding item2, Converter={converter:ValueConverterWithProperties TrueValue=10}}"></CheckBox>
</Grid>

Importing converter from dll into XAML

I have an EnumToBool Converter class in a dll file MicroMVVM. I want to import and create a resource of this class in XAML of my WPF application. Following is how my declaration in XAML looks like:
<Window x:Class="WpfMVVM.MainWindow"
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"
xmlns:local="clr-namespace:WpfMVVM"
xmlns:micro="clr-namespace:MicroMVVM;assembly=MicroMVVM"
Title="MainWindow" Height="350" Width="525" ContentRendered="Window_ContentRendered">
<Window.DataContext>
<!-- Declaratively create an instance of our SongViewModel -->
<local:SabrixQAViewModel />
</Window.DataContext>
<Window.Resources>
<micro:EnumToBoolExtension x:Key="EnumToBool" />
</Window.Resources>
I am getting error in "clr-namespace". The error is "Undefined CLR namespace.The 'clr-namespace' URI refers to a namespace 'MicroMVVM'that is not included in the assembly.
I have added a reference of MicroMVVM.dll in my solution and i am using other classes of the dll in the ViewModel. However, I am getting error while trying to use it in XAML. Please help.
Following is how the Converter class looks inside MicroMVVM:
namespace MicroMvvm
{
public enum ValidationMode
{
GSS,
Digital
}
[ValueConversion(typeof(bool), typeof(Enum))] //This is converting boolean value to a value in Enum
public class EnumToBoolExtension : MarkupExtension, IValueConverter
{
#region IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return parameter.Equals(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((bool)value) == true ? parameter : DependencyProperty.UnsetValue;
}
#endregion
#region MarkupExtension
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
#endregion
}
}
Try to change this:
xmlns:micro="clr-namespace:MicroMVVM; assembly=MicroMVVM"
to:
xmlns:micro="clr-namespace:MicroMvvm;assembly=MicroMVVM"
There is a space between semicolon and the word assembly in your prefix declaration. That will make syntax wrong. Try to remove that space and try again.

Categories

Resources