【问题标题】:Make ViewModel property available for binding to IsChecked使 ViewModel 属性可用于绑定到 IsChecked
【发布时间】:2014-04-19 14:57:53
【问题描述】:

我在我的应用程序中使用 Caliburn.Micro。我想做的是:

  • 在视图中为每个可用许可证创建一个 RadioButton
  • 检查其许可证当前处于活动状态的那个

到目前为止,我的 ViewModel 上有两个属性(我在这里省略了 INotify...Changed 及其实现,因为它有效):

BindableCollection<LicenceInfo> AvailableLicences { get; set; }
LicenceInfo ActiveLicence { get; set; }

在 ViewModel 的构造函数中,我填充了 AvailableLicencesActiveLicence。到目前为止,一切顺利。

目前在视图本身中,我有一个 ItemsControl,其中包含 RadioButtons 和一个不可见的 FrameworkElement 以传递给 MyConverter,在那里我提取了 SelfDataContexts 和不可见的FrameworkElement(其 DataContext 绑定到 ViewModel)并将它们与(覆盖)LicenceInfo.Equals() 进行比较:

<FrameworkElement Name="ActiveLicence" Visibility="Collapsed" />
<ItemsControl Name="AvailableLicences">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <RadioButton cal:Message.Attach="[Event Checked] = [Action ChangeActiveLicence($dataContext)]">
                 <RadioButton.IsChecked>
                     <MultiBinding Converter="{StaticResource MyConverter}" Mode="OneWay">
                         <Binding RelativeSource="{RelativeSource Self}" />
                         <Binding ElementName="ActiveLicence" />
                     </MultiBinding>
                 </RadioButton.IsChecked>
                 [...]

这实际上按预期工作,但在我看来这是一个丑陋的解决方法,我确信我错过了一些东西。

使用&lt;Binding x:Name="ActiveLicence" /&gt;&lt;Binding Path="ActiveLicence" /&gt; 作为第二个参数并删除不可见的FrameworkElement 不起作用,ViewModel 属性未附加到绑定。

我不一定会使用MultiBinding。任何类似于 Caliburn.Micro 操作(例如处理 Checked 事件的操作)也将受到欢迎。有什么想法吗?

【问题讨论】:

  • LicenceInfo 类中只使用IsActive 标志不是一种选择吗?
  • 恐怕不,在这种情况下不是。即使是这样,那也不能解决实际问题。由于我还在学习东西,我会对如何分别处理这类问题非常感兴趣,我哪里错了,或者我错过了什么。
  • 你通常会有一个类似于 ListBox(它从 ItemsControl 派生)的东西,它有一个 SelectedItem 属性并将它绑定到你的 ActiveLicence 视图模型属性。

标签: wpf mvvm binding caliburn.micro


【解决方案1】:

从我的角度来看,如果在 LicenceViewModel 上添加标志不是一种选择,那么您在这里非常接近一个好的解决方案:

不要使用容器框架元素,试试下面的多重绑定:

<MultiBinding Converter="{StaticResource MyConverter}" Mode="OneWay">
    <Binding Path="DataContext" RelativeSource="{RelativeSource Self}" />
    <Binding Path="DataContext.ActiveLicense" RelativeSource="{RelativeSource FindAncestor, AncestorType=ItemsControl}" />
</MultiBinding>

修改转换器以使用Equals() 比较两个对象,与具体类型无关。这样,您就不会乱用不必要的对象,仍然可以正确地分离 ViewsViewModels

编辑:

关于带有标志的替代解决方案:我没有注意到,您的代码中没有涉及 LicenseViewModel... 向许可证信息添加标志不是一个好的解决方案,我同意。您可以考虑将LicenseInfos 包装在LicenseInfoViewModels 中,尽管这需要一些基础设施来实现模型上LicenseInfos 的原始集合与包含ViewModels 的集合之间的同步。

我已就该主题发布了广泛的答案here

然后,当ActiveLicense 属性更改时,您可以将活动许可证的ViewModel 的标志设置为true,并将所有其他标志设置为false。

这是一个特定背景的问题,在这里加倍努力是否有意义。如果您不打算随着时间的推移扩展功能等,而这只是一个简单的许可证选择,那么第一个解决方案可能就足够了。

【讨论】:

  • 我怀疑第二个绑定中的 &lt;Binding ElementName=...&gt; 东西。不应该只是&lt;Binding Path="DataContext.ActiveLicense" RelativeSource=.../&gt;吗?
  • 绝对...已编辑。
  • 稍作修正(&lt;Binding Source="{Binding}" /&gt; 无法编译,所以我使用&lt;Binding Path="DataContext" RelativeSource="{RelativeSource Self}" /&gt;),它按预期工作,非常感谢。我很乐意接受答案,但您表示如果向 LicenceViewModel 添加标志是一种选择,那么还有另一种解决方案。好吧,这实际上是一种选择。我不能做的是向LicenceInfo 类添加一个标志。
  • @Hannes:我已经编辑了我的答案,也许新的方面会有所帮助。不过,我认为您对第一个解决方案很满意。
  • 在我问这个问题之前,我还考虑了您建议的附加标志解决方案,包括它的优点和缺点。第一个解决方案的简单性使其非常有吸引力,并且非常适合我在这种特殊情况下的需求,所以这就是我暂时坚持的。未来需求变化时,“加倍努力”仍然可以做到。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-08
  • 1970-01-01
  • 2015-07-24
  • 2013-06-25
  • 2011-02-01
  • 2011-08-26
  • 1970-01-01
相关资源
最近更新 更多