c# - UWP-x :Bind Mode=TwoWay throws errors without converter

标签 c# win-universal-app

有一个类似的问题,但答案似乎与原始问题不符。

我有一个 DataTemplate,里面有 3 个组合框。前两个工作正常,但第三个会引发编译错误。

<ComboBox ItemsSource="{x:Bind ListOne, Mode=OneWay}" 
              SelectedItem="{Binding SelectedOne, Mode=TwoWay}"
              DisplayMemberPath="Name"/>
<ComboBox ItemsSource="{x:Bind ListTwo}" 
              SelectedItem="{x:Bind SelectedTwo, Mode=TwoWay, Converter={StaticResource GenericConverter}}"
              DisplayMemberPath="Name"/>
<ComboBox ItemsSource="{x:Bind ListThree}" 
              SelectedItem="{x:Bind SelectedThree, Mode=TwoWay}"
              DisplayMemberPath="Name"/>

对于 ListOne,“绑定(bind)”按原样完美工作。

对于 ListTwo,“x: Bind”只有在添加值转换器时才有效。 “GenericConverter”仅返回传入的“值”。除此之外,它什么都不做。

对于 ListThree,没有值转换器,编译器会抛出错误:

"Invalid binding path 'SelectedThree': Cannot bind type 'IdNameVm' to 'SystemObject' without a converter.

在所有情况下,ItemSource 都是一个 ObservableCollection,所选项目的类型为 IdNameVm。

使用转换器是可行的,但被迫在 x: Bind 上放置一个虚拟转换器感觉是错误的,只是为了让 XAML 进行编译。

根据要求,这里是 ObservableCollection 加上 IdNameVm 的定义方式:

public ObservableCollection<IdNameVm> ListOne { get; set; }


public class IdNameVm : BindableBase
{
    private int _id;
    private string _name;

    public int Id
    {
        get { return _id; }
        set { Set(ref _id, value); }
    }

    public string Name
    {
        get { return _name; }
        set { Set(ref _name, value); }
    }

    protected bool Equals(IdNameVm other)
    {
        return Id == other.Id;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((IdNameVm)obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            var hashCode = Id;
            return hashCode;
        }
    }
}

最佳答案

如果您查看 ComboBox 的文档,您会看到 ItemsSource 和 SelectedItem属性都是对象类型。控件在不知道它正在处理什么类型的 View 模型的情况下运行。因此,您基本上可以将任何类型的集合传递给 ItemsSource。 SelectedItem 在不知道它正在处理什么类型的对象的情况下工作。

这种行为在传统的双向 {Binding} 中运行良好,因为绑定(bind)是在运行时评估的。所以{Binding}可以在运行时将SelectItem的对象类型转换为IdNameVm。

但是,{x:Bind} 的情况有些不同。正如您所注意到的,单向绑定(bind)有效——这是因为您的 ObservableCollection 可以隐式转换为对象(ItemsSource 的类型)和 IdNameVm 转换为对象(SelectedItem 的类型)。但是双向绑定(bind)将不再有效,因为编译器无法将对象(SelectedItem 的类型)转换为 IdNameVm。你需要一个转换器。

就像您可以在 C# 中执行此操作一样:

IdNameVm vm = new IdNameVm();
object selectedItem = vm;

但是你不能这样做:

IdNameVm vm = new IdNameVm();
object selectedItem = vm;
IdNameVm vm2 = selectedItem; // You need: IdNameVm vm2 = (IdNameVm)selectedItem;

注释中的cast是XAML中的converter。

在这些情况下,最简单的方法是使用传统的{Binding}。

关于c# - UWP-x :Bind Mode=TwoWay throws errors without converter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36158167/

相关文章:

c# - 将 Azure 移动服务连接到 UWP

mvvm - 使用 MVVM 模式的具有多帧的 UWP 应用

xaml - 本地化 UWP 中 XAML UI 中的字符串

c# - 是否存在字段优于自动属性的情况

c# - 在 C# 中从字符串中剪切

c# - Appbar 后面的弹出窗口

c# - 如何在 XAML 中使默认属性不同于内容?

c# - 重命名数据表中的行

c# - 连续调用 NetworkStream.Write - 它有什么不同吗?

c# - 为什么实现具有相同属性的多个接口(interface)显示 'ambiguity' 警告?