Reputation: 18805
Currently I have markup like this
<TextBlock>
<TextBlock.Text>
<Binding Path="Value" ElementName="window" ConverterParameter="M">
<Binding.Converter>
<local:DatePartValueConverter />
</Binding.Converter>
</Binding>
</TextBlock.Text>
</TextBlock>
I'd like to shorten it to something like this
<TextBlock Text="{Binding Path=Value,ElementName=window,
ConverterParameter=M,Converter={local:DatePartValueConverter}}" />
But the compiler barfs because DatePartValueConverter isn't derived from MarkupExtension. Is there no other way to get the short form markup to create an instance of DatePartValueConverter?
Incidentally I tried deriving from MarkupExtension and it does solve the problem. My implementation of ProvideValue looked like this
public override object ProvideValue(IServiceProvider serviceProvider)
{
return new DatePartValueConverter();
}
and it works, but I remain hazy on the origin and nature of serviceProvider
and what one might be expected to do with it.
Interestingly, when I used the Visual Studio 2012 binding editor on a binding that used this markup extension it promptly expanded it again, making the whole markup extension support thing a bit pointless.
I should probably mention that I need a private instance for each binding because it maintains internal state - it needs to know the whole DateTime value to set some aspect, like this
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
culture = System.Globalization.CultureInfo.CurrentCulture;
var strValue = value as string;
int y = _value.Year, M = _value.Month, d = _value.Day,
H = _value.Hour, m = _value.Minute, s = _value.Second;
if (strValue == null)
return null;
else
{
string p = parameter as string;
switch (p)
{
case "yyyy":
y = int.Parse(strValue); break;
case "yy":
y = (strValue.Length == 4) ?
int.Parse(strValue) :
int.Parse(DateTime.Now.Year.ToString().Substring(0, 2) + strValue);
break;
case "M":
case "MM":
M = int.Parse(strValue); break;
...
}
}
return new DateTime(y, M, d, H, m, s);
}
Upvotes: 0
Views: 295
Reputation: 71936
You can create an instance of DatePartValueConverter
as a resource, then use it.
<Window.Resources>
<local:DatePartValueConverter x:Key="datePartValueConverter" />
</Window.Resources>
<TextBlock Text="{Binding Path=Value, ElementName=window,
ConverterParameter=M, Converter={StaticResource datePartValueConverter}}" />
EDIT If you did want to make the converter a MarkupExtension
then you can do so. You can either return a new instance in ProvideValue
or you can return the current instance with return this;
By returning the current instance you can have properties in your converter, and allows you to do things like this.
public class DatePartValueConverter : MarkupExtension, IValueConverter {
public string ParseType { get; set; }
// other methods
}
<TextBlock Text="{Binding Path=Value, ElementName=window,
Converter={local:DatePartValueConverter ParseType=M}}" />
As for IServiceProvider
see MarkupExtension.ProvideValue — Is the IServiceProvider actually used?
Upvotes: 3
Reputation: 20086
The only way other than deriving your converter from MarkupExtension
that I know of is creating your own custom binding class (take a look at DelayBinding
).
Upvotes: 1