简体   繁体   English

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

[英]What is the proper way to bind to a value while showing a friendly name from a list of presets also defined on that item?

Got a tough one. 有一个艰难的。 Consider a ViewModel that is comprised of a list of objects, where each object defines an int value, and some of those objects also define a Presets dictionary of ints keyed on a 'friendly' string representing that value in the UI. 考虑一个ViewModel,它由一个对象列表组成,其中每个对象定义一个int值,其中一些对象还定义了一个Presets字典,该字典是在一个'友好'字符串上键入的,该字符串表示UI中的该值。

Here's an example... 这是一个例子......

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; }
}

The goal for the UI is if the item has no presets, the user can enter any int value they want. UI的目标是如果项目没有预设,用户可以输入他们想要的任何int值。 However, if there are presets, we want to limit them to those values and also display them in the UI as the Friendly names from the dictionary. 但是,如果预设,我们要限制他们只能使用这些值,并且在UI从字典中的友好名称显示出来。

Our first attempt was to use a TextBox and a ComboBox, modifying their visibilities depending on if there were presets or not, like this... 我们的第一次尝试是使用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

...but when we're using this in a DataTemplate of a list that supports virtualization, the combo occasionally displays blanks. ...但是当我们在支持虚拟化的列表的DataTemplate中使用它时,组合偶尔会显示空白。 I believe is because when the item is reused and the DataContext changes, SelectedValue updates before ItemsSource meaning there's potentially no preset value to match on, thus the proposed SelectedValue value gets tossed by the control, then ItemsSource updates, but there's no selected value so it shows a blank. 我相信是因为当重新使用项目并且DataContext更改时,SelectedValue会在ItemsSource之前更新,这意味着可能没有匹配的预设值,因此建议的SelectedValue值被控件抛出, 然后 ItemsSource更新,但是没有选定的值,所以它显示一个空白。

My next thought (and what we preferred anyway) was to use only a TextBox that displayed the preset name but was actually bound to Value, then use a converter to work its magic, and let the user type either the friendly name or the actual value. 我的下一个想法(以及我们最喜欢的)是仅使用显示预设名称但实际上绑定到Value的TextBox,然后使用转换器来实现其魔力,并让用户键入友好名称或实际值。 If the user typed something that wasn't a valid value or a preset, we'd just throw an error. 如果用户键入的内容不是有效值或预设,我们只会抛出错误。 If there were no presets, it would simply act as a pass-through of the value. 如果没有预设,它只会作为价值的传递。

However, there I'm not sure how to pass in the presets to the converter. 但是,我不知道如何将预设传递给转换器。 You can't set a binding on a ConverterParameter to pass them in that way, and if you use a multi-binding, then I'm not sure how to structure the 'ConvertBack' call since there too I need them passed in, not sent back out. 你不能在ConverterParameter上设置绑定以这种方式传递它们,如果你使用多重绑定,那么我不知道如何构造'ConvertBack'调用,因为我也需要它们传入,而不是送回去了。

I'm thinking the proper way is to implement UiValue in the ViewModel which we'd simply bind to like this... 我认为正确的方法是在ViewModel中实现UiValue,我们只需将它绑定到这样......

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

...then move the code that would've been in the converter to that property's getter/setter implementation, or simply be a pass-through to Value if there are no presets. ......然后移动会一直在转换到该属性的getter / setter方法实现的代码,或者仅仅是一个直通如果没有预置值。 However, this seems like too much logic is going in the ViewModel where it should be in the View (ala a converter or similar.) Then again, maybe that's exactly the point of the ViewModel. 然而,这看起来似乎在ViewModel中的逻辑过多,它应该在View中(转换器或类似物)。然后,也许这正是ViewModel的重点。 I dunno. 我不知道。 Thoughts welcome. 欢迎思考。

Personally, I would go for putting the 'converter code' into the property as you suggested... I don't see any problem with having the code in there. 就个人而言,我会按照你的建议把'转换器代码'放到属性中...我没有看到在那里有代码的任何问题。 In fact, it's probably better than having it in a Converter because then you can easily test it too. 事实上,它可能比在Converter使用它更好,因为那样你也可以轻松测试它。

Sorry, this isn't much of an answer, but I felt that your question deserved at least one. 对不起,这不是一个很好的答案,但我觉得你的问题至少应该有一个。

I like your question, because it illustrates the way of thinking that stands behind the existence of a ViewModel in WPF. 我喜欢你的问题,因为它说明了在WPF中存在ViewModel背后的思维方式。 Sometimes they seem inevitable. 有时他们似乎不可避免。

Converters are designed to be stateless, which is why it's difficult to pass context variables like presets . 转换器被设计为无状态,这就是为什么很难传递像presets这样的上下文变量。 ViewModel is a layer, of which responsibility is to prepare Model for binding purposes. ViewModel是一个层,其职责是为绑定目的准备Model The role of a "model" is to handle logic. “模型”的作用是处理逻辑。 Thus, a ViewModel may handle in detail the behaviour (logic) of a View . 因此, ViewModel可以详细处理View的行为(逻辑)。 This is precisely what you want. 这正是你想要的。 Most of the time I find myself not needing Converters at all. 大多数时候我发现自己根本不需要转换器。

Sometimes it feels more natural that the view logic should be in the View , but then ViewModel seems superfluous. 有时感觉更自然,视图逻辑应该是在View ,但随后ViewModel似乎是多余的。 However, when that logic is located in the ViewModel it's usually easier to auto-test. 但是,当该逻辑位于ViewModel ,通常更容易进行自动测试。 I wouldn't be afraid of putting stuff like this in ViewModel at all. 我根本不会害怕在ViewModel中放置这样的东西。 Often this is the easiest (and correct) way. 通常这是最简单(和正确)的方式。

Have UiValue property in ViewModel and handle conversion there: ViewModelUiValue属性并处理转换:

public string UiValue{ get{/*...*/} set{/*...*/} }

To rephrase, in WPF there is no clean way to replace the property you bind to. 换句话说,在WPF中没有干净的方法来替换绑定的属性。 Eg if you wanted to have 例如,如果你想拥有

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

change at some point to: 在某些时候改变为:

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

you're trapped. 你被困了。 This is not how things are done. 这不是事情的完成方式。 Better have a constant binding like 最好有一个像常量一样的绑定

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

and deal with the logic behind the UiValue property. 并处理UiValue属性背后的逻辑。

Another possible approach (instead of playing with visibility of ComboBox and TextBox ) is to have a DataTemplateSelector, which would decide whether a ComboBox or TextBox should be created for SomeItem . 另一种可能的方法(而不是使用ComboBoxTextBox可见性)是有一个DataTemplateSelector,它决定是否应该为SomeItem创建一个ComboBox或TextBox。 If presets are null or empty select TextBox-based DataTemplate , otherwise take ComboBox. 如果presets为null或为空,则选择基于TextBox的DataTemplate ,否则选择ComboBox。 If I'm not mistaken you'd have to investigate FrameworkElement.DataContext property from within the selector to find the context ( presets ). 如果我没弄错,你必须从选择器中调查FrameworkElement.DataContext属性来查找上下文( presets )。

Considering your doubt about ConvertBack method, most commonly value or Binding.DoNothing is returned in case you don't need conversion in any of the directions. 考虑到您对ConvertBack方法的疑问,如果您不需要在任何方向进行转换,则最常返回valueBinding.DoNothing

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从语言文件绑定动态值的正确方法是什么? - What is the proper way to bind a dynamic value from a language file? 从BlockingCollection中获取项目的正确方法是什么? - What is the proper way to take an item from a BlockingCollection? 从字典更改名称到友好名称的Winform绑定下拉列表 - Winform bind dropdown from dictionary change name to a friendly name 从列表中删除项目的正确方法是什么 <WeakReference<T> &gt;? - What is the proper way to remove items from a List<WeakReference<T>>? 在我的模型中定义列表并显示每个列表的项目计数的正确方法是什么? - What is the proper way to define a list in my model and display item counts for each list? 从单个嵌套的XElement中检索值的正确方法是什么? - What is the proper way to retrieve a value from a single, nested, XElement? 扫描二维码时显示 Json 列表中的项目 - Showing item from Json list while scanning QR code 在XML中存储文件名的正确方法是什么? - What is the proper way to store a file name in XML? 在MVVM / MVVM Light中绑定单选按钮的正确方法是什么 - What is the proper way to bind a radio button in MVVM / MVVM Light 在树视图中指定数据上下文并绑定分层数据的正确方法是什么? - What is the proper way to designate the data context and bind hierarchical data in the treeview?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM