遇到了一个艰难的。考虑一个由对象列表组成的 ViewModel,其中每个对象定义一个 int 值,并且其中一些对象还定义了一个 Presets 字典,该字典键控在 UI 中表示该值的“友好”字符串上。
这是一个例子......
List<SomeItem> AllItems;
public class SomeItem : INotifyPropertyChanged
{
public SomeItem(int initialValue, Dictionary<int,string> presets)
{
this.CurrentValue = initialValue;
this.Presets = presets;
}
public int CurrentValue{ get; set; } // Shortened for readability. Assume this property supports INPC
public Dictionary<int,string> Presets{ get; private set; }
}
UI 的目标是如果项目没有预设,用户可以输入他们想要的任何 int 值。但是,如果有预设,我们希望将它们限制为这些值,并将它们作为字典中的友好名称显示在 UI 中。
我们的第一次尝试是使用 TextBox 和 ComboBox,根据是否有预设来修改它们的可见性,就像这样......
<ComboBox ItemsSource="{Binding Presets}"
DisplayMemberPath="Key"
SelectedValuePath="Value"
SelectedValue="{Binding CurrentValue, Mode=TwoWay}"
Visibility={Binding HasPresets, Converter=...}">
<TextBox Text="{Binding CurrentValue}"
Visibility={Binding HasPresets, Converter...}" /> // Assume the inverse of the combo
...但是当我们在支持虚拟化的列表的 DataTemplate 中使用它时,组合偶尔会显示空白。我相信是因为当项目被重用并且 DataContext 发生变化时, SelectedValue 在 ItemsSource 之前更新,这意味着可能没有预设值可以匹配,因此提议的 SelectedValue 值被控件抛出,然后ItemsSource 更新,但没有选择值所以它显示空白。
我的下一个想法(无论如何我们更喜欢)是只使用一个显示预设名称但实际上绑定到 Value 的 TextBox,然后使用转换器来发挥它的魔力,让用户输入友好名称或实际值. 如果用户输入的内容不是有效值或预设值,我们只会抛出错误。如果没有预设,它只会充当值的传递。
但是,我不确定如何将预设传递给转换器。您不能在 ConverterParameter 上设置绑定以以这种方式传递它们,如果您使用多重绑定,那么我不确定如何构造“ConvertBack”调用,因为我也需要传入它们,而不是送回去了。
我认为正确的方法是在 ViewModel 中实现 UiValue ,我们只需像这样绑定到它......
<TextBox Text="{Binding UiValue}" />
...然后将转换器中的代码移动到该属性的 getter/setter 实现,或者如果没有预设,则只是传递给 Value。但是,这似乎在 ViewModel 中出现了太多的逻辑,它应该在 View 中(ala 转换器或类似的)。再说一次,也许这正是 ViewModel 的重点。我不知道。欢迎提出想法。