I've created a small user control consisting of a button whose content is an Image. I created an "ImageSource" dependency property on the user control in order to bind to it from the Image inside the button.
However in the XAML where I placed an instance of my user control setting the property throws an error at runtime :
<ctrl:ImageButton ImageSource="/Resources/Images/Icons/x.png" Command="{Binding Reset}" DisabledOpacity="0.1"/>
and at runtime :
'/Resources/Images/Icons/x.png' string is not a valid value for 'ImageSource' property of type 'ImageSource'. 'ImageSource' type does not have a public TypeConverter class.
I then created a converter :
public class StringToBitmapImage : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return new BitmapImage(new Uri((string) value, UriKind.RelativeOrAbsolute));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and then decorated my dependency property with it :
[TypeConverter(typeof(StringToBitmapImage))]
public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register(
LambdaHelper.GetMemberName<ImageButton>(ib => ib.ImageSource), typeof (ImageSource), typeof (ImageButton));
[TypeConverter(typeof(StringToBitmapImage))]
public ImageButton ImageSource
{
get { return (ImageButton)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
but still WPF does not convert my string to an ImageSource (BitmapImage) instance...
What to do?
There are several incorrect things here:
First, your CLR property is returning an ImageButton whereas the dependency property is defined as an ImageSource.
Second, a type converter is not the same as a binding value converter. Your type converter should derive from TypeConverter and be applied on the ImageSource class rather than on the property itself.
Third, the framework ImageSource type already has a TypeConverterAttribute with ImageSourceConverter as the type converter so everything should work out of the box without having to write a custom converter. Make sure you're not referencing another custom ImageSource class in another namespace.
To finish, use ImageBrush.ImageSource.AddOwner rather than redefining a whole new dependency property.
Edit: to answer Berryl's comment:
public static readonly DependencyProperty ImageSourceProperty = ImageBrush.ImageSource.AddOwner(typeof(ImageButton);
This piece of code will reuse the existing ImageSource property rather than defining a new (remember that each different dependency property gets registered in a global static dictionary), only defining a new owner and optionally a new metadata. It's like OverrideMetadata but from an outside class.
Related
I create columns in codebehind as such.. each column is bound to a property.
Dim column_selected As New DataGridCheckBoxColumn()
column_selected.Header = "Selected"
column_selected.Binding = New Binding("IsChecked")
dgvResults.Columns.Add(column_selected)
I want to be able to hide a column, based on a checkbox or something of that nature, where I can hide/show them at will.
I've heard about binding visibility to a property Boolean, but i'm not sure how to do that when the columns are created in code behind.
Any idea on how to accomplish this? Say I want to have a single checkbox that hides a specific column, if you unchecked it, it shows it.
If logic of setting column visibility doesn't contains any business logic and this is clear UI operation. Then I think you can just put it in the code-behind, what is wrong with that?
XAML
<CheckBox Checked="HideColumn" Unchecked="UnhideColumn"/>
Code-behind
Protected Sub HideColumn()
'your code
End Sub
Protected Sub UnhideColumn()
'your code
End Sub
You can set Binding normally from code-behind, but since System.Visibilty is enum, you have to use Converter (an instance of IValueConverter interface) to set Binding correctly. There are a lots of possible implementation, the following is an example:
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool? vis = value as bool?;
return (vis.HasValue && vis.Value) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
After that, the only thing you should do is to set the Converter property of your Binding to the new instance of BoolToVisibilityConverter as follows:
column_selected.Binding.Converter = new BoolToVisibilityConverter()
And that's all.
public static readonly DependencyProperty SingleGridLengthProperty = DependencyProperty.Register("SingleGridLength", typeof(double), typeof(MapConverter));
public class MapConverter : DependencyObject, INotifyPropertyChanged, IMultiValueConverter
{
public double SingleGridLength
{
get { return (double)GetValue(MapConverter.SingleGridLengthProperty); }
set
{
SetValue(MapConverter.SingleGridLengthProperty, value);
OnNotifyPropertyChanged("SingleGridLength");
}
}
<local:MapConverter x:Key="MapConverter"
SingleGridLength="{Binding SingleGridLength, RelativeSource={RelativeSource Self}}" />
I have a converter with a set of dependency properties bound in the .xaml
The problem I am having is each property is "getting" and returning the value but it never "sets" the value. Am I allowed to use dependency properties in converters? Or should I be approaching this a different way? Thanks in advance!
First, your binding is invalid. You are binding the SingleGridLength property to itself. You would need to bind it to another property/object.
Second, you shouldn't raise the OnNotifyPropertyChanged in the setter for your SingleGridLength property. You only need to do that for regular CLR properties. Dependency properties have a built in change notification system that Binding hooks into.
Take a look at the PropertyChangedCallback delegate that you can specify in the PropertyMetadata constructor. The callback will be invoked when the property value of your dependency property changes, and you can place your handling code within this callback method.
I suggest using a Converter basing on IValueConverter?
The converter then should only do the calculation from the input to the output format. The value returned by the converters
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
and
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
will be used by the property you did the binding on.
See: http://msdn.microsoft.com/de-de/library/system.windows.data.ivalueconverter.aspx
I´m trying to make an application that has to be able to easily change a dll file which could change colors in the application.
I´m trying to use resource manager to do this but am having problems with setting color values so that the styles for views can easily accept it.
We know that(in this case) the background of a button takes in SolidColorBrush, and while
Value="Black" works,
Value={x:Static res:AppResources.Btn_Background}
which gives the string Black does not (current theory being that converters make the former work but not the latter).
This is all being done in wpf & mvvm.
Have you guys an idea about how this could be done.
Greetings
You could use a Binding:
Background="{Binding Source={x:Static res:AppResources.Btn_Background}}"
This will cause the CoerceValue to fire for the DependencyProperty controlling the background.
#Snowbear mentioned it may be a Color rather than a String, in which case you would need to provide a trivial IValueConverter.
public class ColorConverter: IValueConverter
{
#region IValueConverter Members
private Dictionary<Color, Brush> brushes = new Dictionary<Color, Brush>();
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
Brush brush;
var color = (Color)value;
if (!brushes.TryGetValue(color, out brush))
{
brushes[color] = brush = new SolidColorBrush(color);
brush.Freeze();
}
return brush;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Your specific issue is that you are bypassing the default string to Brush conversion and would need to handle that manually.
As sixlettervariables states, you'd can use a Binding if your source is a string, but that is probably overkill. At a minimum, you'd want to set Mode=OneTime on the Binding.
You can also create a custom MarkupExtension that performs the conversion.
Your conversion, whether it be through a custom IValueConverter or MarkupExtension, can leverage the BrushConverter class. So things like "Black" or "#000" will work as they do when defining the color in XAML like your first example.
EDIT:
Actually a markup extension that derives from StaticExtension, makes this easier:
public class BrushStaticExtension : StaticExtension {
private static BrushConverter converter = new BrushConverter();
public BrushStaticExtension() { }
public BrushStaticExtension(string member) : base (member) { }
public override object ProvideValue(IServiceProvider serviceProvider) {
return converter.ConvertFrom(base.ProvideValue(serviceProvider));
}
}
If you specify a string then XAML parser uses a converter from string which automatically creates a SolidColorBrush. As far as I understand at the moment Btn_Background resource is Color but it should be a SolidColorBrush instead.
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}"
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