XAML doesn't see my IValueConverter class - c#

I'm creating a simple WP8, but I'm having troubles hiding (changing the Visibility property) on a control.
In XAML I've added xmlns:local="clr-namespace:MyProjectName" (I've also tried with using).
The XAML is then structured as follows:
<phone:PhoneApplicationPage
x:Class="MyProjectName.Pages.Main"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyProjectName"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d"
shell:SystemTray.IsVisible="True" Margin="0,4,0,-4" Background="#FFBD3F3F">
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneBackgroundBrush}" >
<Grid x:Name="ContentPanel" Grid.Row="1" >
<Grid.Resources>
<local:VisibilityFormatter x:Key="FormatConverter" />
</Grid.Resources>
<phone:LongListSelector Grid.Row="4">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Obj}"
Visibility="{Binding ObjVisibility,
Mode=OneWay,
Converter={StaticResource FormatConverter}}" />
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
</Grid>
The problem is at the <local:...> line: The name "VisibilityFormatter" does not exist in the namespace "clr-namespace:MyProjectName".
The class is defined as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
namespace MyProjectName
{
public class Formatter
{
public class VisibilityFormatter : IValueConverter
{
// Retrieve the format string and use it to format the value.
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var visibility = parameter as bool?;
return visibility.HasValue && visibility.Value ? Visibility.Visible : Visibility.Collapsed;
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
}
The class ObjInfo is a simple public class with two properties:
namespace MyProjectName.Models
{
public class ObjInfo
{
public bool ObjVisibility { get; set; }
public string Obj { get; set; }
}
}
It's similar to this question, but no migrating is involved. I'm developing on WP8 from the get-go.
What am I trying to achieve? Well. I'm storing whether the control should be visible or not in that bool property. Since the XAML control's property only grokks the Visibility enum, but not bool, I need to convert it to that enum.

The VisibilityFormatter is an inner class of the Formatter class. You don't really need the Formatter class, just make the VisibilityFormatter a top class, and the XAML parser will find it.
Also, the general naming convention for converters is XXXConverter and not XXXFormatter, but that's no rule.

You don't have MyProjectName.VisibilityFormatter in your project, you have
MyProjectName.Formatter.VisibilityFormatter
You should remove Formatter class and leave only:
namespace MyProjectName
{
public class VisibilityFormatter : IValueConverter
{
// Retrieve the format string and use it to format the value.
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var visibility = parameter as bool?;
return visibility.HasValue && visibility.Value ? Visibility.Visible : Visibility.Collapsed;
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

Related

WPF: ValueConverter (IValueConverter) does not work

I have a Window class, where I have several TextBlock elements which should receive a Background color by a value of a Binding property. The first "Converter binding" works fine and does everything expected. Today I tried to implement another "Converter binding" with another Converter used for it, but it does not work:
(I left out the ConvertBack methods because they are not necessary here):
namespace InsightTool.Gui.Helper {
[ValueConversion(typeof(double), typeof(Brush))]
public class AverageExecutionTimeToColorConverter : IValueConverter {
public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
double val;
double.TryParse(value.ToString(), out val);
if (val >= 10000) {
return Brushes.Red;
} else if (val >= 5000) {
return Brushes.Orange;
} else {
return Brushes.Green;
}
}
}
[ValueConversion(typeof(int), typeof(Brush))]
public class ThreadsAvailableCountToColorConverter : IValueConverter {
public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
int val;
int.TryParse(value.ToString(), out val);
if (val < 100) {
return Brushes.Red;
} else if (val < 200) {
return Brushes.Orange;
} else if (val < 500) {
return Brushes.Yellow;
} else {
return Brushes.Green;
}
}
}
}
In the Window class I used both converts as following:
<Window ...
x:Name="Main"
xmlns:Base="clr-namespace:InsightTool.Gui.Helper">
<Window.Resources>
<Base:ThreadsAvailableCountToColorConverter x:Key="ThreadsAvailableCntConverter"/>
<Base:AverageExecutionTimeToColorConverter x:Key="AvgExecutionTimeConverter"/>
</Window.Resources>
<!-- This one works fine-->
<TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ExecutionTimeAverage, Converter={StaticResource AvgExecutionTimeConverter}, ElementName=UCExecutionTimes}"/>
<!-- This one does not work-->
<TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ThreadsAvailableCount, Converter={StaticResource ThreadsAvailableCntConverter}, ElementName=Main}"/>
</Window>
Declaration of DependencyProperties:
public partial class UserControlExecutionTimes : UserControl {
public static readonly DependencyProperty ExecutionTimeAverageProperty =
DependencyProperty.Register("ExecutionTimeAverage", typeof(double), typeof(MainWindow), new FrameworkPropertyMetadata(double));
public double ExecutionTimeAverage {
get { return (double)GetValue(ExecutionTimeAverageProperty); }
set { SetValue(ExecutionTimeAverageProperty, value); }
}
}
public partial class MainWindow : Window {
public static readonly DependencyProperty ThreadsAvailableCountProperty = DependencyProperty.Register("ThreadsAvailableCount", typeof(int),
typeof(MainWindow), new FrameworkPropertyMetadata(int));
public int ThreadsAvailableCount {
get { return (int)GetValue(ThreadsAvailableCountProperty); }
set { SetValue(ThreadsAvailableCountProperty, value); }
}
}
Both DependencyProperties are set correctly and their values are displayed in the GUI. What do I miss here?
EDIT:
I also tested the following:
<Window>
<!-- This one works fine-->
<TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ThreadsAvailableCount, Converter={StaticResource AvgExecutionTimeConverter}, ElementName=Main}"/>
<!-- This one does not work-->
<TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ThreadsAvailableCount, Converter={StaticResource ThreadsAvailableCntConverter}, ElementName=Main}"/>
</Window>
It seems that there is a problem for the Binding to consume the return value of the "new" converter, but I have no clue why.
EDIT2
I check the bindings with Snoop and the result was the following:
The background property of the working converter binding looks like this:
But the background property of the not working converter binding looks this:
Another proof that ThreadsAvailableCount is set correctly (Binding to a Textblock):
It more and more seems to be a mistake in displaying the return value of the ThreadsAvailableCountToColorConverter. That is because in Debug mode, it stops at a breakpoint in the Convert method of the ThreadsAvailableCountToColorConverter. It even reachesreturn in the Convert method successfully.
Ah! Finally solved this. I had the exact same problem. With a TextBlock, with an IValueConverter converting to a Brush.
The binding was working, no errors or output. The value was getting into the IValueConverter code, I could debug right through to the return statement then... nothing!
You've done everything right, but you've automatically imported the wrong Brushes. I do it all the time with WPF.
replace the using statement:
using System.Drawing
with:
using System.Windows.Media
WPF uses System.Windows.Media.Brushes, but it's very easy to import the almost identical System.Drawing.Brushes and not notice. It all looks fine, until WPF gets hold of it and can't actually use it. But it fails 'gracefully' by falling back on the default colour.
I think could be multiple issues look at the 'output window' for binding expression errors.
1) Ensure that the textbox are rendered in separate areas and are not
overlapping.
2) Use relative path to get to the control and use it property in the binding expression
Your convertor looks fine.
Following is my xaml
<Window x:Class="StackOverflowBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:stackOverflowBinding="clr-namespace:StackOverflowBinding"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<stackOverflowBinding:ThreadsAvailableCountToColorConverter x:Key="ThreadsAvailableCntConverter"/>
<stackOverflowBinding:AverageExecutionTimeToColorConverter x:Key="AvgExecutionTimeConverter"/>
</Window.Resources>
<Grid>
<!--<DatePicker
x:Name="newtally"
Text="{Binding CustomerLastTally,Mode=TwoWay}"
Margin="0 0 0 0"
/>-->
<!-- This one works fine-->
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Width="30" Height="30" Text="Break"/>
<TextBlock Grid.Row="1" Grid.Column="0" Width="30" Height="30" VerticalAlignment="Center" Text="Break" Background="{Binding ExecutionTimeAverage, Converter={StaticResource AvgExecutionTimeConverter}, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
<!-- This one does not work-->
<TextBlock Grid.Row="2" Grid.Column="0" Width="30" Height="30" VerticalAlignment="Center" Text="Break" Background ="{Binding ThreadsAvailableCount, Converter={StaticResource ThreadsAvailableCntConverter}, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
</Grid>
</Window>
Following is my code behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace StackOverflowBinding
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// Dependency Property
public static readonly DependencyProperty ExecutionTimeAverageProperty =
DependencyProperty.Register("ExecutionTimeAverage", typeof(DateTime),
typeof(MainWindow), new FrameworkPropertyMetadata(DateTime.Now));
// .NET Property wrapper
public DateTime ExecutionTimeAverage
{
get { return (DateTime)GetValue(ExecutionTimeAverageProperty); }
set { SetValue(ExecutionTimeAverageProperty, value); }
}
// Dependency Property
public static readonly DependencyProperty ThreadsAvailableCountProperty =
DependencyProperty.Register("ThreadsAvailableCount", typeof(int),
typeof(MainWindow), new FrameworkPropertyMetadata(40));
// .NET Property wrapper
public int ThreadsAvailableCount
{
get { return (int)GetValue(ThreadsAvailableCountProperty); }
set { SetValue(ThreadsAvailableCountProperty, value); }
}
}
}
Following is my convertor
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Media;
namespace StackOverflowBinding
{
[ValueConversion(typeof(double), typeof(Brush))]
public class AverageExecutionTimeToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double val;
double.TryParse(value.ToString(), out val);
if (val >= 10000)
{
return Brushes.Red;
}
else if (val >= 5000)
{
return Brushes.Orange;
}
else
{
return Brushes.Green;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
[ValueConversion(typeof(int), typeof(Brush))]
public class ThreadsAvailableCountToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int val;
int.TryParse(value.ToString(), out val);
if (val < 100)
{
return Brushes.Red;
}
else if (val < 200)
{
return Brushes.Orange;
}
else if (val < 500)
{
return Brushes.Yellow;
}
else
{
return Brushes.Green;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

WPF Set the value of a property to a ratio of the value of another property

I was wondering if in XAML without touching the view model I could do something like this or this except use a ratio of the other property.
I have a button control with 2 ellipses inside and I want the margin of one of the ellipses to vary depending on the height of the other.
So something like:
<Ellipse Margin=.2*"{Binding ElementName=OtherEllipse, Path=Height}"/>
MainWindow.xaml
<Window x:Class="MultiBindingConverterDemo.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:MultiBindingConverterDemo"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="800">
<StackPanel>
<StackPanel.Resources>
<local:MultiplyValueConverter x:Key="MultiplyValueConverter"/>
</StackPanel.Resources>
<Ellipse x:Name="OtherEllipse" Width="100" Height="50" Fill="Red"/>
<Ellipse Width="50" Height="50" Fill="Blue"
Margin="{Binding Path=Height,
ElementName=OtherEllipse,
Converter={StaticResource MultiplyValueConverter},
ConverterParameter=0.2}">
</Ellipse>
</StackPanel>
MainWindow.xaml.cs
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace MultiBindingConverterDemo
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class MultiplyValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double height = (double)value;
double multiplier = double.Parse((string)parameter);
return new Thickness(height * multiplier);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
You can, you need to write custom IValueConverter. http://www.codeproject.com/Tips/868163/IValueConverter-Example-and-Usage-in-WPF
And if you need to pass a parameter: Passing values to IValueConverter

Unknown property 'Converter' for type 'MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension' encountered while parsing a Markup Extension

I am binding to an ObservableCollection called ScaleFactor to a ComboBox. The value of the ObservableCollection are simply 1, 2, 4 and 8. I want to use an IValueConverter to change these values to x1, x2, x4 and x8.
My MainWindow.xaml
<Window x:Class="TimeLineCanvas.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:timeline="clr-namespace:TimeLineCanvas.UserControls"
xmlns:helper="clr-namespace:TimeLineCanvas.Helpers"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<helper:ZoomConverter x:Key="ZoomConverter" />
</Grid.Resources>
<StackPanel>
<ComboBox ItemsSource="{Binding SSS}" HorizontalAlignment="Left" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding, Converter={StaticResource ZoomConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Grid>
</Window>
And the code behind
using System;
using System.Windows;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace TimeLineCanvas
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
#region Constructors
public MainWindow()
{
InitializeComponent();
SSS = new ObservableCollection<int>();
SSS.Add(1);
SSS.Add(2);
this.DataContext = this;
}
#endregion
public ObservableCollection<int> SSS { get; set; }
}
}
And the converter
using System;
using System.Windows.Data;
namespace TimeLineCanvas.Helpers
{
public class ZoomConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return "x" + value.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
I don't know why this is, I'm not using MarkupExtensions so I don't think this link helps. Can any one shed any light?
Do not use a comma after Binding. This way you call the empty constructor on the Binding object.
{Binding, Converter={StaticResource ZoomConverter}}
should be
{Binding Converter={StaticResource ZoomConverter}}

problem for bind radiobutton to database

Please following my code :
<Grid DataContext="{Binding ElementName=dataGrid_services, Path=SelectedItem}"
Width="766">
<RadioButton Content="visit" IsChecked="{Binding Path=type_services}"
FontFamily="Tahoma"/>
i want to bind ischecked property from radiobutton but return value is not false or true.
the value is string. please help me how to bind this value?
thanks in advance
Use an IValueConverter.
Given this window containing your radiobutton and associated bindings:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525" x:Name="dataGrid_services">
<Window.Resources>
<local:CheckedConverter x:Key="converter"/>
</Window.Resources>
<Grid DataContext="{Binding ElementName=dataGrid_services, Path=SelectedItem}" Width="766">
<RadioButton Content="visit" IsChecked="{Binding Path=type_services, Converter={StaticResource converter}}" FontFamily="Tahoma"/>
</Grid>
The changes are adding a namespace reference for local (or whichever namespace your converter is in):
xmlns:local="clr-namespace:WpfApplication1"
creating the converter resource:
<Window.Resources>
<local:CheckedConverter x:Key="converter"/>
</Window.Resources>
and using the converter resource:
IsChecked="{Binding Path=type_services, Converter={StaticResource converter}}"
The converter looks like this and simply converts from string to boolean.
public class CheckedConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string typeService = value as string;
if (typeService == "Yes it is")
{
return true;
}
if (typeService == "Nope")
{
return false;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool typeService = (bool)value;
if (typeService)
{
return "Yes it is";
}
else
{
return "Nope";
}
}
}
You'll have to define a value converter to convert from string to boolean and use it with your RadioButton.
public class StringToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return Convert.ToBool(value);
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return Convert.ToString(value);
}
}
and in XAML, use
<RadioButton Content="visit" IsChecked="{Binding Path=type_services, Converter={StaticResource stringToBoolConverter}}"
FontFamily="Tahoma"/>
where stringToBoolConverter is defined in the resources of a parent element.
<Window.Resources>
<local:StringToBoolConverter x:Key="stringToBoolConverter" />
</Window.Resources>

WPF Slider and dates

I want to make slider to select dates. For example, every hour in last two days. Also slider should has a legend on the bottom with values. How could I do it?
I made slider with data context as DoubleCollection from total hours in date and changed tooltip using custom ValueConverter. But when I change value, tooltip shows real values - total hours in date. Also I have no idea how to add a legend.
Here is a working example. First we create a slider from 0 to 48 rounded to integer values (TickFrequency="1" IsSnapToTickEnabled="True") then add a TextBlock bound to the slider value.
A ValueConverter is used to convert the 0-48 value into a date.
<Window x:Class="StackOverflow2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StackOverflow2"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:HourToDateConverter x:Key="MyHourConverter"/>
</Window.Resources>
<StackPanel>
<Slider x:Name="MySlider" Minimum="0" Maximum="48" TickFrequency="1" IsSnapToTickEnabled="True"/>
<TextBlock Text="{Binding ElementName=MySlider, Path=Value, Converter={StaticResource MyHourConverter}}" HorizontalAlignment="Center"/>
</StackPanel>
</Window>
And the code behind:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace StackOverflow2
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class HourToDateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
object result = DependencyProperty.UnsetValue;
if (value is double)
result = DateTime.Now.Date.AddHours((double)value);
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

Categories