Dependency Property: Getting but not Setting - wpf

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

Related

Hiding columns from datagrid when autogenerate=false

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.

How can a ViewModel request data from a view when it needs it?

I have a calculated property on my View that I need to bind to my ViewModel. I'm using WPF and it seems that there is no way to make a bindable property (Dependency Property) that is self calculating. I don't want to perform the calculations whenever the View's state changes because they are time intensive. I want to do the calculations whenever the ViewModel needs the result, i.e. when it closes.
Based on your comment above, I'd use a Converter
Your ViewModel would contain the encrypted data, and the binding to the View uses a Converter which converts it into something readable. When it's time to save the data back to the ViewModel, use the ConvertBack method of the converter to encrypt the data again.
<TextBox Text="{Binding EncryptedAccountNumber,
Converter={StaticResource DecryptTextConverter}}" />
public class DecryptTextConverter: IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
// Implement decryption code here
return decryptedValue;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
// Implement encryption code here
return ecryptedValue;
}
}
If the Encryption code takes a while, set your UpdateSourceTrigger=Explicit and manually trigger the source update when the Save button is clicked.
This is my solution. It works the same way as ICommand but the view provides the delegate (CalculationDelegate) and the view model calls CanExecute and Execute. Its not pure MVVM but it works.
public interface ICalculationProvider<TResult>
{
event EventHandler CanExecuteChanged;
Func<TResult> CalculationDelegate { get; set; }
bool CanExecute();
TResult Execute();
bool TryExecute(out TResult a_result);
}
I have marked Rachel's answer as correct, simply because what I am doing here is not pure MVVM.

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}"

ImageSource dependency property on a user control - XAML value set throws

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.

WPF: Binding Hierarchy

I have defined a default binding in my style.
For example I have configured the visibility binding of my button so that it must not be visible if the relative command can not execute.
This is my default binding behavior.
Apart from my default behavior, every view can customize the buttons it uses with another visibility binding.
I want to combine the two bindings so that if any of two say "it's not visible" it will be not visible!
In other words, is it possibile to create a binding behavior hierarchy? Thanks!
use a MultiBinding to wire up all the different bindings in XAML, and write your own IMultiValueConverter that prioritises / ands / ors each value as you like. You can't use a MultiBinding without an IMultiValueConverter (or a StringFormat, but that's no use to you)
Note that PriorityBinding is NOT what you are looking for here.
here's a valueConverter you can use:
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BooleansAndToVisibilityMultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
Func<bool, bool, bool> aggregator = (x, y) => x && y;
bool aggregate = values.Cast<bool>().Aggregate(aggregator);
return aggregate ? Visibility.Visible : Visibility.Collapsed;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
No, sorry, not possible in XAML.
You CAN do this combination in code, though. You can write a BindingConverter for this.

Resources