简体   繁体   中英

DisplayMemberPath with Indexer in WPF

Starting situation

I want to show a list of ICameraInfo in a ComboBox.
ICameraInfo is an interface that give you many infos of a camera. You get each info using indexer .

In my case I want to display the parameter ICameraInfo[CameraInfoKey.FriendlyName] in the ComboBox (CameraInfoKey is a static class).

Code

In ViewModel:

using Basler.Pylon;
...
public List<ICameraInfo> CamerasFound { get => CameraFinder.Enumerate(); }

In View:

<Window
...
xmlns:bpy="clr-namespace:Basler.Pylon;assembly=Basler.Pylon"/>
...
<ComboBox Name="CamerasList" ItemsSource="{Binding CameraFound }" DisplayMemberPath="[bpy:CameraInfoKey.FriendlyName]" />

Issue

But the binding can't get the value (the ItemsSource isn't the problem, if I remove DisplayMemberPath the list is displayed)
绑定错误

I'm not sure about the bpy namespace in XAML to get the static property CameraInfoKey.FriendlyName and according to the documentation it is possible to use indexers with Binding, but I'm not sure about the usage either.

Do you know where the error may have come from?

The part between the square brackets in the Binding Path can not be a variable. When you write

DisplayMemberPath="[bpy:CameraInfoKey.FriendlyName]"

the string "bpy:CameraInfoKey.FriendlyName" is passed to the indexer property.

A simple solution may be to use the value of the CameraInfoKey.FriendlyName property in XAML.

Assuming a declaration similar to

public class CameraInfoKey
{
    public static string FriendlyName { get; } = "friendly_name";
}

the following XAML would work:

DisplayMemberPath="[friendly_name]"

If ICameraInfo does not have FriendlyName property that you want and you must get the actual value from an indexer property, I don't think that DisplayMemberPath is the way for you to go. Instead, you should probably layout the ItemTemplate for your ComboBox and in it, have a TextBlock that pulls the string value. You could even use a converter for this if necessary. For example, something like this:

// Takes an ICamerInfo value and a string parameter of the key and returns the result of the indexer

public class CameraInfoPropertyConverter: IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is not ICameraInfo info)
            return DependencyProperty.UnsetValue;

        if (parameter is not string key)
            return DependencyProperty.UnsetValue

        return info[key];
    }
}

Then, instead of DisplayMemberPath , your ComboBox uses the ItemTemplate and relies on the converter to go get the property from the indexer

<ComboBox Name="CamerasList" ItemsSource="{Binding CameraFound }">
    <ComboBox.Resources>
        <MyNameSpace:CamerInfoPropertyConveter x:Key="InfoConverter"/>
    </ComboBox.Resources>

    <ComboBox.ItemTemplate>
        <DataTemplate DataType="{x:Type MyNameSpace:ICameraInfo}">
            <TextBlock Text="{Binding Converter={StaticResource InfoConverter}, 
                                      ConverterParameter="{x:Static bpy:CameraInfoKey.FriendlyName}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

Note that I didn't compile this or anything. And I'm assuming that bpy:CameraInfoKey.FriendlyName is truly a statically available string value

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM