值转换器在第 2 个 运行 失败,但使用 try catch C# 成功

Value converter fails on 2nd run but succeeds with try catch C#

我有一个组合框,它在我的 ViewModel 中填充了一组对象。

<ComboBox x:Name="ChangelistComboBox"
          SelectedIndex="{Binding MyObjectSelectionIndex, Mode=TwoWay}"
          ItemsSource="{Binding MyObjectList, Mode=OneWay}"
          Margin="5"
          Grid.Column="0">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={StaticResource MyObjectToComboBoxConverter}}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

我正在使用转换器将对象中的参数转换为显示在组合框中的显示字符串

[ValueConversion(typeof(MyObject), typeof(string))]
class MyObjectToComboBoxConverter : ValueConverterBase
{
    public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        try {
            MyObject theObject = (MyObject)value;
            int id = theObject.Id;
            return (((id != -1) ? id.ToString() : "default") + " : " + theObject.Description);
        } catch(InvalidCastException e) {
            return (String)value;
        }
    }

    public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        return new MyObject(); //Not used
    }
}
    abstract class ValueConverterBase : IValueConverter
{
    public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
        return DependencyProperty.UnsetValue;
    }
    public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
        return DependencyProperty.UnsetValue;
    }
}

在模型中,列表定义为:

        private ObservableCollection<MyObject> _MyObjectList;
    public ObservableCollection<MyObject> MyObjectList {
        get
        {
            if (_MyObjectList != null) { return _MyObjectList; } else { return new ObservableCollection<MyObject>(); }
        }
        set
        {
            if (_MyObjectList != value) {
                _MyObjectList = value;
                NotifyPropertyChanged("MyObjectList");
            }
        }
    }

在 ViewModel 中,MyObjectList 只是通过接口从模型中引用:

        public ObservableCollection<MyObject> MyObjectList {
        get
        {
            if (Model != null) {
                return Model.MyObjectList;
            } else {
                return new ObservableCollection<MyObject>();
            }
        }
    }

如果没有 TryCatch,这个转换器会在我的 MyObjectList 更新时崩溃。它会在 MyObject theObject = (MyObject)value;

上给出类似 Cannot cast type string to object 的错误

使用 TryCatch,转换器按预期工作。它甚至 returns 一个正确组装的字符串。问题是我在错误日志中得到了 InvalidCastExceptions,这是不好的。我也不知道为什么尽管有例外它仍然有效。

我唯一的预感是,由于某种原因,对象被转换了两次,一次是从对象到字符串,然后它试图将字符串转换为字符串,但失败了。我不明白为什么它会那样做。

MVVM IValueConverter Convert method getting empty string argument when expecting a float

刚刚发现这似乎与我遇到的问题相同。我不完全理解那里给出的解释,但如果修改 Convert 以接受空字符串是一个可行的解决方案,我可以接受

仍然感觉像个黑客,但我猜乞丐不能挑剔

您将 ComboBox 源绑定到 MyObject 的列表,因此该值绝不能为字符串类型。我猜你的模型状态有问题。

您绑定视图的方式是正确的,也是转换器的第一个版本:

[ValueConversion(typeof(MyObject), typeof(string))]
class MyObjectToComboBoxConverter : IValueConverter
{
    public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        try {
            var theObject = (MyObject)value;
            var id = theObject.Id;
            return (((id != -1) ? id.ToString() : "default") + " : " + theObject.Description);
        } catch(InvalidCastException e) {
            return (string)value;
        }
    }

    public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        throw new NotImplementedException();
    }
}

请开始将您的 ViewModel 更改为:

public ObservableCollection<MyObject> MyObjectList { get; set; } = new ObservableCollection<MyObject>();

您需要在 MyObject 模型 (https://docs.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-create-and-bind-to-an-observablecollection) 的属性上实施 OnPropertyChangeEvent 所以你只需要将 ViewModel 中的 ObservableCollection 默认设置为一个空实例。

然后添加项目:

MyObjectList.Add(new MyObject{ id=1, Description="First"});