Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在显示项目上定义的预设列表中的友好名称时,绑定到值的正确方法是什么?_C#_Wpf_Binding_Ivalueconverter_Imultivalueconverter - Fatal编程技术网

C# 在显示项目上定义的预设列表中的友好名称时,绑定到值的正确方法是什么?

C# 在显示项目上定义的预设列表中的友好名称时,绑定到值的正确方法是什么?,c#,wpf,binding,ivalueconverter,imultivalueconverter,C#,Wpf,Binding,Ivalueconverter,Imultivalueconverter,有一个很难的。考虑一个VIEW模型,它包含一个对象列表,其中每个对象定义一个int值,其中一些对象还定义了一个预设的INTS的字典,它在一个友好的字符串中表示UI中的值。 这里有一个例子 List<SomeItem> AllItems; public class SomeItem : INotifyPropertyChanged { public SomeItem(int initialValue, Dictionary<int,string> presets)

有一个很难的。考虑一个VIEW模型,它包含一个对象列表,其中每个对象定义一个int值,其中一些对象还定义了一个预设的INTS的字典,它在一个友好的字符串中表示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; }
}
列出所有项目;
公共类SomeItem:INotifyPropertyChanged
{
公共SomeItem(int initialValue,字典预设)
{
this.CurrentValue=初始值;
这个。预设=预设;
}
public int CurrentValue{get;set;}//因可读性而缩短。假定此属性支持INPC
公共字典预设{get;private set;}
}
UI的目标是,如果项目没有预设,用户可以输入他们想要的任何int值。但是,如果存在预设,我们希望将它们限制为这些值,并将它们作为字典中的友好名称显示在UI中

我们的第一次尝试是使用一个文本框和一个组合框,根据是否有预设来修改它们的可视性,就像这样

<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
<TextBox Text="{Binding UiValue}" />
//假设组合的倒数
…但当我们在支持虚拟化的列表的DataTemplate中使用此选项时,组合框偶尔会显示空白。我认为这是因为当项目被重用并且DataContext发生更改时,SelectedValue会在ItemsSource之前更新,这意味着可能没有可匹配的预设值,因此建议的SelectedValue值会被控件抛出,然后ItemsSource会更新,但没有选定值,因此显示为空白

我的下一个想法(也是我们更喜欢的)是只使用一个文本框,该文本框显示预设名称,但实际绑定到值,然后使用转换器发挥其魔力,让用户键入友好名称或实际值。如果用户输入的值或预设值无效,我们只会抛出一个错误。如果没有预设,它将只是作为值的传递

但是,我不确定如何将预设传递到转换器。您不能在ConverterParameter上设置绑定来以这种方式传递它们,如果您使用多重绑定,那么我不确定如何构造“ConvertBack”调用,因为我也需要传入它们,而不是发回

我认为正确的方法是在ViewModel中实现UiValue,我们只需像这样绑定它

<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
<TextBox Text="{Binding UiValue}" />


…然后将转换器中的代码移动到该属性的getter/setter实现,或者如果没有预设,则将其作为值的传递。然而,这似乎是ViewModel中的逻辑太多了,它应该在视图中(ala转换器或类似的)然后,也许这正是ViewModel的观点。我不知道。欢迎您的想法。

就我个人而言,我会按照您的建议将“转换器代码”放入属性中。。。我认为代码在里面没有问题。事实上,它可能比把它放在
转换器中要好,因为这样你也可以很容易地测试它


对不起,这不是一个很好的答案,但我觉得你的问题至少值得一个

我喜欢你的问题,因为它说明了WPF中存在的
ViewModel
背后的思维方式。有时它们似乎是不可避免的

转换器被设计成无状态的,这就是为什么很难传递像
预设这样的上下文变量的原因
ViewModel
是一个层,其职责是为绑定目的准备
Model
。“模型”的作用是处理逻辑。因此,
ViewModel
可以详细处理
视图的行为(逻辑)。这正是你想要的。大多数时候,我发现自己根本不需要转换器

有时,视图逻辑应该位于
视图中感觉更自然,但是
视图模型似乎是多余的。但是,当该逻辑位于
ViewModel
中时,通常更容易进行自动测试。我一点也不怕把这样的东西放到
ViewModel
中。通常这是最简单(也是正确)的方法

ViewModel
中具有
UiValue
属性,并在其中处理转换:

public string UiValue{ get{/*...*/} set{/*...*/} }
换言之,在WPF中,没有干净的方法来替换绑定到的属性。如果你想

<TextBox Text="{Binding IntValue}" />

在某一点上更改为:

<TextBox Text="{Binding PresetValue}" />

你被困住了。事情不是这样做的。最好有一个像这样的常数绑定

<TextBox Text="{Binding UiValue}" />

并处理
UiValue
属性背后的逻辑

另一种可能的方法(而不是玩弄
ComboBox
TextBox
的可见性)是使用DataTemplateSelector,它将决定是否应该为
SomeItem
创建组合框或文本框。如果
预设值
为空或为空,请选择基于文本框的
数据模板
,否则选择组合框。如果我没有弄错的话,您必须从选择器中调查
FrameworkElement.DataContext
属性,以找到上下文(
预设


考虑到您对
ConvertBack
方法的怀疑,最常见的是
value
Binding。如果您不需要在任何方向上进行转换,则会返回DoNothing

+1以获得一个解释得很好的问题。LOL。。。谢谢是的,你和另一个答案似乎得出了和我一样的结论。。。把它放在ViewModel中。DataTemplateSelector代码会有和我现在面临的相同的问题。。。如果该值设置在ItemsSource之前,则该值将被抛出。(我在用于此类测试的“游乐场”应用程序中确认了这一点。)我认为关键在于绑定到视图上定义的属性,然后在后面的代码中将实际绑定设置为