How to reference a sub class for IValueConverter? - wpf

I have read this SOF Post: How to properly reference a class from XAML
But i cannot get this work.
Because my converter class is subclass, i cannot get reference on XAML.
The Converter Class:
using System;
using System.Windows;
using System.Windows.Data;
namespace GapView.Classes
{
public class ConverterClass
{
public class PhotoBorderConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int width = System.Convert.ToInt32(value);
return width + 16;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int width = System.Convert.ToInt32(value);
return width - 16;
}
}
}
}
And the MainWindow.xaml, XML section, i add
xmlns:GapView="clr-namespace:GapView"
xmlns:Classes="clr-namespace:GapView.Classes"
Inside
<Classes:ConverterClass x:Key="BorderConverter" />
Finally, i apply to Border element.
And SettingThumbWidth is a TextBox element.
<Border Width="{Binding Path=Text , ElementName=SettingThumbWidth, Converter={StaticResource BorderConverter}}" Height="166" >
When i press "." after BorderConverter, the subclass PhotoBorderConverter won't show and it seems i cannot access.
So how can i fix this?
It because it possible have other Converter, so i want to centralized in one ConvertClass.
Thanks you.

Your decision to centralize into ConverterClass is kind of weird and unnecesary. You can keep all your converters in one file, but you don't need to encapsulate them within an outer class.
With what you currently have, try using the correct namespace like this:
xmlns:converters="clr-namespace:GapView.Classes.ConverterClass"
<converters:PhotoBorderConverter x:Key="BorderConverter" />

Related

How do I bind a DataGrid Width to a converter?

I want to include the size of the VerticalScrollbar when i define the width of a DataGrid.
So far i wrote a Converter:
[ValueConversion(typeof(double), typeof(double))]
public class VerticalScrollbarConverter : IValueConverter
{
#region IValueConverter Member
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is double)
return (double)value + SystemParameters.VerticalScrollBarWidth;
else
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
I included my converter in the xaml namespace with:
xmlns:Core="clr-namespace:Core;assembly=SMS_Core"
And I defined the converter as a (window) resource:
<Window.Resources>
<Core:VerticalScrollbarConverter x:Key="VerticalScrollbarConverter"/>
</Window.Resources>
Since all of my DataGrid.Columns have a fixed Value I know the value that i need to pass.
How do I tell my GridView Width property in xaml to use the converter?
I know that my question is pretty basic. As you can tell I am very new to WPF.
Thanks in advance for every hint. If you need some more info or context just ask away.
The comment from sa_ddam213 didn't exactly solve the problem. But it sure did push me into the right direction.
To pass the value automatically I had to do the following:
I created a property in the window class called TotalColumnWidth. Returning this:
myDataGrid.Columns.Sum(c => c.ActualWidth);
The xaml is the following:
Width="{Binding ElementName=_Root, Path=TotalColumnWidth, Converter={StaticResource ResourceKey=VerticalScrollbarConverter}}"
Using the converter mentioned above.

WPF: How to populate combobox with enum in Xaml

I know there are several ways to do it, but I would like to make it even easier if possible because I have a lot of comboboxes to bind in this way. There is a suggestion using ObjectDataProvider here. The problem is that I have to create a resource entry for each enum and that's a lot. So far, I have been using the code-behind way because it's much shorter:
cmb.ItemsSource = Enum.GetValues(typeof(MyTypes));
I'm wondering if an equivalent can be produced in Xaml. I thought we could archive this by using a converter. We could convert the type to an array and then bind the array to combobox' ItemsSource. But I got stuck on how to specify my enum to the converter. Here is my code:
My enum:
public enum MyTypes { Type1, Type2, Type3 };
This is my converter:
public class EnumToArrayConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Enum.GetValues(value.GetType());
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null; // I don't care about this
}
}
My Xaml Resource:
<lib:EnumToArrayConverter x:Key="E2A"/>
Here is how to use it:
<ComboBox SelectedItem="{Binding MyType}" ItemsSource="{Binding MyTypes, Converter={StaticResource E2A}}"/>
So, my question is how to specify my enum "MyTypes" to the converter. I also tried to prepend namespace, but it doesn't help.
You would be better off with a MarkupExtension, like this one.
CodeNaked posts a great way of doing this
For your approach to work you can change the converter to Enum.GetValues(value as Type) and use the x:Type syntax as Source for the Binding
ItemsSource="{Binding Source={x:Type local:MyValues},
Converter={StaticResource EnumToArrayConverter}}"
EnumToArrayConverter
public class EnumToArrayConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Enum.GetValues(value as Type);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null; // I don't care about this
}
}

ComboBox of Types with a ValueConverter and Custom Attributes

I'm using MVVM, in case it makes a difference.
My MainWindowViewModel has two DependencyProperties, TheList, and TheSelectedItem. TheList is a List<Type>, TheSelectedItem is a Type.
The MainWindow has a ComboBox. When the MainWindowViewModel loads it grabs a list of all the classes in the assembly that implement IMyInterface and sets TheList to this.
Each of these classes has a custom attribute applied called DisplayName, which has one parameter, that will be used to show a user-friendly name for the class instead of the name the application knows about for the class.
I've also got a ValueConverter for the express purpose of converting these types into the display names.
public class TypeToDisplayName : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (targetType.Name == "IEnumerable")
{
List<string> returnList = new List<string>();
if (value is List<Type>)
{
foreach (Type t in value as List<Type>)
{
returnList.Add(ReflectionHelper.GetDisplayName(t));
}
}
return returnList;
}
else
{
throw new NotSupportedException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return typeof(BasicTemplate);
}
}
So, what I wind up with is a ComboBox with a list of names in it that the user should be able to understand. Awesome! This is just what I want!
Next step: I bind the SelectedItem property of my ComboBox to my TheSelectedItem property in my ViewModel.
Here's the problem: When I make a selection, I get a little red box around my ComboBox and the TheSelectedItem property on my ViewModel never gets set.
I'm pretty sure it's because of a type mismatch (the items in the ComboBox appear to be strings now, and TheSelectedItem is of type Type--also, when I change TheSelectedItem to a string instead of a Type, it works). But I don't know where I need to start coding to convert the (hopefully unique) DisplayName that's in the ComboBox back to a Type object.
Thanks in advance for any help. I'm pretty stumped on this one.
If I understand your question correctly then you use that Converter on the ItemsSource for the ComboBox? In that case I think you can let the ItemsSource be like it is and instead just Convert each type when they are presented like this.
<ComboBox ...>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=typeName, Converter={StaticResource TypeToDisplayNameConverter}}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
And then just convert each type in the Converter.
public class TypeToDisplayNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Type t = (Type)value;
return ReflectionHelper.GetDisplayName(t);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
}
Make sure you have IsSynchronizedWithCurrentItem set to true on the ComboBox. Check this out...

WPF: Is there a way to use a ValueConverter without defining a resource?

Is there a way to use a ValueConverter without defining it in a resource? As is the syntax is pretty verbose.
You can use a MarkupExtension to minimise the amount of xaml code required. E.g:
public class MyConverter: MarkupExtension, IValueConverter
{
private static MyConverter _converter;
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
// convert and return something
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
// convert and return something (if needed)
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (_converter == null)
_converter = new MyConverter();
return _converter;
}
}
You end up with a syntax like this:
{Binding Converter={conv:MyConverter}}
This approach has an added advantage of ensuring that all your converters are singletons.
This article does a great job of explaining the concept and provides sample code.
Within your converter you can have a static property or field that you can refer to in xaml. No need for adding a resource.
public class MyConverter : IValueConverter
{
public static readonly MyConverter Instance = new MyConverter();
... }
And in XAML
<TextBlock Text="{Binding Path=., Converter={x:Static l:MyConverter.Instance}}" />
Beaware that these converters should not store any state as the same instance will be used.
If you are iffy about public fields just create a static property instead.
Though it is debatable that this is better
You could create an attach property to hook up to the binding and perform the conversion, though if the only reason is for breverity, I wouldn't recommend adding an extra piece of complexity to your code.
How exactly are you declaring these converters such that verbosity is an issue?
<conv:NegatingConverter x:Key="NegatingConverter" />
One line per converter per application.
Usage isn't verbose either.
Converter="{StaticResource NegatingConverter}"

Display WinForm Image in WPF application

I have a dll with quite a bit of System.Drawing.Image resources that I have wrapped into static properties so I can update them dynamically.
I would like to use the images through xaml in a WPF application, but the only way I can figure is to do it through the code behind manually.
Is there a way to do the winform to wpf image convertion on a static property in xaml?
You could bind to your images directly, using a converter. Here is an example in a window:
<Window.Resources>
<WinForms2WPFImageConverter x:Key="WF2WPFDrawingConverter" />
</Window.Resources>
...
This SO question has a drawing converter, which I adapted here as a ValueConverter.
public class WinForms2WPFImageConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
System.Drawing.Image i = (System.Drawing.Image) value;
using (MemoryStream drawingStream = new MemoryStream())
{
i.Save(drawingStream);
i.Seek(0, SeekOrigin.Begin);
return System.Windows.Media.Imaging.BitmapFrame.Create(drawingStream);
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new InvalidOperationException();
}
}
Of course, you need to account for namespaces in the declaration of the resource.
I advise not using static properties, in order to leverage INotifyPropertyChanged (or dependency properties), so that the display automatically changes when the properties point to other images.
(note: this was typed, not copied from VS, so there may be a syntax error somewhere.)
You could bind to your images using a Method in WPF. Here is an example in a link
http://microsoftdotnetsolutions.blogspot.com/2016/07/convert-winforms-image-to-wpf.html

Resources