WPF difficult binding: bind value to IConverter with as input the result from a static method
I was wondering if it's possible to have the following type of binding, and I couldn't form a search query that gave me definitive answer, or find it anywhere.
Here is the case.
I have a ListBox with 'Items' (a custom class) these items are displayed using an item template. I use a converter to calculate the back ground color. See below:
<Window.Resources>
<local:MyConverter x:Key="myConverter"/>
</Window.Resources>
<!-- snip -->
<ListBox Grid.Row="2" Name="listBoxMaterialType" Margin="0,0,0,0" ItemsSource="{Binding Path=MyItems, ElementName=MySource}">
<ListBox.ItemTemplate>
<DataTemplate>
<Te开发者_开发问答xtBlock Text="{Binding DisplayText}" Background="{Binding Converter={StaticResource myConverter}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now for better abstraction I would like MyConverter to not convert an Item, but only to convert the score of an item. An item does not know it's own score, but the score is calculated by calling MyStaticClass.MyStaticMethod(item); So in code I would like to do a binding like this: myTextBlock.Background= MyConverter(MyStaticClass.MyStaticMethod(item)); is it possible to do this in WPF with data binding?
Traditionally it would be the role of the ViewModel to take the your domain object and expose the data required by the view. This can include adding new properties which are aggregates or conversions of model properties (e.g. Supplying a FullName property by concatenating the FirstName and Surname model properties). In your case:
public class Item
{
public string DisplayText { get; set; }
}
public class ItemViewModel
{
private Item _model;
public string DisplayText
{
get { return _model.DisplayText; }
}
public int Score
{
get { return MyStaticClass.MyStaticMethod(_model);
}
}
Then, using the ViewModel as your DataContext, you can bind your converter directly to the Score property.
You can do a lot of things, e.g. you could add a few properties to your converter which point it towards a method. Those could be for example TargetType
, TargetObject
& MethodName
, then you can - by specifying MethodName
and either of the other properties - make the converter call the method on the TargetObject
or statically.
e.g. something like this:
//<Property declarations>
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool staticCall = TargetObject == null;
var types = new Type[] { value.GetType() };
var args = new object[] { value };
MethodInfo method;
if (staticCall)
{
method = TargetType.GetMethod(MethodName, types);
}
else
{
method = TargetObject.GetType().GetMethod(MethodName, types);
}
var score = method.Invoke(TargetObject, args);
//Convert score
}
(As with all sketchy snippets, do not mindlessly copy-paste this, it probably sucks)
<vc:MyConverter x:Key="ScoreConverter"
TargetType="{x:Type local:MyStaticClass}"
MethodName="MyStaticMethod"/>
Of course the converter does its work, by applying the static function you're describing: from an item to a color. Everything goes well.
The problem would arise if you consider that the color may change upon some condition on the score. In which way do you think the binding can be triggered to update the color value (thus calling the converter)?
I guess that it's much more a structural problem instead of a technical one.
EDIT: Either I don't understand the problem, or the solution is straightforward:
public class MyConverter
: IValueConverter
{
public object Convert(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture)
{
return MyStaticClass.MyStaticMethod(value as MyItem);
}
public object ConvertBack(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I'd add Mode=OneTime to the binding clause as well.
Cheers
精彩评论