【问题标题】:How do you bind user control properties to properties of an observable object contained in observable collection如何将用户控件属性绑定到可观察集合中包含的可观察对象的属性
【发布时间】:2020-06-05 09:11:25
【问题描述】:

我正在使用 MVVMLight,并且需要能够在视图初始化期间对大约 12 个切换框的属性进行编程编辑。由于它们太多了,我想遍历链接的属性,我尝试使用 ObservableCollectionObservableObject 包含要绑定到切换按钮属性的值。我不确定这是绑定问题还是继承自 ObservableObjectINotifyPropertyChanged 接口的错误实现。

这是包含我希望绑定到的属性的类:

public class CavitySelect : ObservableObject
{
    private string _Text;
    public string Text
    {
        get { return _Text; }
        set
        {
            _Text = value;
            RaisePropertyChanged("Text");
        }
    }
    private bool _Visible;
    public bool Visible
    {
        get { return _Visible; }
        set
        {
            _Visible = value;
            RaisePropertyChanged("Visible");
        }
    }
    private bool _Toggle;

    public bool Toggle
    {
        get { return _Toggle; }
        set
        {
            _Toggle = value;
            RaisePropertyChanged("Toggle");
        }
    }

    public CavitySelect()
    {
        Text = "";
        Visible = false;
        Toggle = false;
    }
}

这是我的ObservableCollection的实例化:

private ObservableCollection<CavitySelect> _CavTogglesProperties;
public ObservableCollection<CavitySelect> CavTogglesProperties
{
    get { return _CavTogglesProperties; }
    set
    {
        _CavTogglesProperties = value;
        RaisePropertyChanged("CavTogglesProperties");
    }
}

public MyViewModel()
{
    this.CavTogglesProperties = GetCavities();
}    

public ObservableCollection<CavitySelect> GetCavities()
{
    CavitySelect t11 = new CavitySelect();
    CavitySelect t12 = new CavitySelect();
    CavitySelect t13 = new CavitySelect();
    CavitySelect t14 = new CavitySelect();
    CavitySelect t15 = new CavitySelect();
    CavitySelect t16 = new CavitySelect();
    CavitySelect t26 = new CavitySelect();
    CavitySelect t21 = new CavitySelect();
    CavitySelect t22 = new CavitySelect();
    CavitySelect t23 = new CavitySelect();
    CavitySelect t24 = new CavitySelect();
    CavitySelect t25 = new CavitySelect();
    ObservableCollection<CavitySelect> temp = new ObservableCollection<CavitySelect>() {t11,t12,t13,t14,t15,t16,t21,t22,t23,t24,t25,t26};
    return temp;
}

这是我尝试绑定它的方式:

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BoolToVisibilty"/>
</Window.Resources>
<Grid Background="#FFF4F4F5" Margin="8,165,8,8"  DataContext="{Binding CavTogglesProperties}">
    <ToggleButton DataContext="{Binding t11}" Content="{Binding Text}" IsChecked="{Binding Toggle}" Visibility="{Binding Visible,Converter={StaticResource BoolToVisibilty}}"/> 
</Grid>

我已确认 View 与 ViewModel 类的绑定工作正常。我也尝试过绑定而不首先设置包含网格的DataContext,例如:

<ToggleButton DataContext="{Binding CavTogglesProperties[t11]}" ... />

为了澄清: 每个 CavitySelect 项都与 GridView 中的一个切换按钮相关,并且属性将基于未显示的输入进行初始化。

【问题讨论】:

  • 您想显示一个 ToggleButtons 列表,CavTogglesProperties 中的每个项目都有一个吗?还是只显示 CavTogglesProperties 中的单个项目?
  • 用两种解释来回答。希望对您有所帮助!
  • 我希望能够以编程方式更改哪些 ToggleButtons 可见及其文本。
  • 太棒了。在这种情况下,请看一下我的答案的前半部分 - 显示项目集合。这显示了如何使用 ListView,并指向另一个问题,解释如何向为 ListView 供电的集合添加过滤器。然后,您可以根据需要根据“可见”属性进行过滤。

标签: c# wpf mvvm mvvm-light observablecollection


【解决方案1】:

显示项目集合

您的问题并没有说得很清楚,但我相信您想在 UI 中显示项目列表;但是,按照目前的实现,您的 XAML 的结构实际上是显示单个项目。

要显示列表,您需要查看各种集合视图中的任何一个(例如ListViewGridView 等)。

例如:

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BoolToVisibilty"/>
</Window.Resources>
<Grid Background="#FFF4F4F5" Margin="8,165,8,8">
  <ListView ItemsSource="{Binding CavTogglesProperties}">
    <ListView.ItemTemplate>
      <DataTemplate>
        <ToggleButton Content="{Binding Text}" IsChecked="{Binding Toggle}" />
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</Grid>

要仅显示特定项目,您应该在 ViewModel 中过滤列表,而不是绑定可见性。如果可见的项目在显示时没有改变,只需在填充列表时过滤列表即可。

但是,如果可见性将发生变化,并且您希望视图反映这些变化,请查看为您的项目源实施过滤器,如以下问题所述:How do I Filter ListView in WPF?

因为您已经在使用 ObservableCollection 和 ObservableObject,所以一切都应该自动更新。

显示集合中的单个项目

如果我读错了你的问题,并且你想知道如何显示集合中的单个项目,有几种不同的方法可以解决这个问题:

  1. 将单个项目公开为 ViewModel 上的属性,这样视图就不必深入列表。
  2. 创建一个converter,接收集合和索引,然后取出正​​确的项目。

不过,我强烈建议使用选项 1,因为它最符合 MVVM,生成最干净和最可测试的代码。

例如:

private ObservableCollection<CavitySelect> _CavTogglesProperties;
public ObservableCollection<CavitySelect> CavTogglesProperties
{
    get { return _CavTogglesProperties; }
    set
    {
        _CavTogglesProperties = value;
        RaisePropertyChanged("CavTogglesProperties");
    }
}

private CavitySelect _SpecificCavToggle;
public CavitySelect SpecificCavToggle
{
    get { return _SpecificCavToggle; }
    set
    {
        _SpecificCavToggle= value;
        RaisePropertyChanged("SpecificCavToggle");
    }
}

public MyViewModel()
{
    this.CavTogglesProperties = GetCavities();
    this.SpecificCavToggle = this.CavTogglesProperties[0];
}    

public ObservableCollection<CavitySelect> GetCavities()
{
    CavitySelect t11 = new CavitySelect();
    CavitySelect t12 = new CavitySelect();
    CavitySelect t13 = new CavitySelect();
    CavitySelect t14 = new CavitySelect();
    CavitySelect t15 = new CavitySelect();
    CavitySelect t16 = new CavitySelect();
    CavitySelect t26 = new CavitySelect();
    CavitySelect t21 = new CavitySelect();
    CavitySelect t22 = new CavitySelect();
    CavitySelect t23 = new CavitySelect();
    CavitySelect t24 = new CavitySelect();
    CavitySelect t25 = new CavitySelect();
    ObservableCollection<CavitySelect> temp = new ObservableCollection<CavitySelect>() {t11,t12,t13,t14,t15,t16,t21,t22,t23,t24,t25,t26};
    return temp;
}

【讨论】:

  • 对于造成的误解,我深表歉意,我应该提到我删除了大量代码以提高可读性。我相信你答案的后半部分就是我要找的。这两种方法似乎都表明视图将无法直接与 Observable Collection 中的各个元素进行通信。这是正确的吗?
  • 我的回答是基于演示。因此,根据您是要展示整个系列还是单个项目,请参阅我的答案的单独部分。无论您使用哪种表示技术,您都可以使用 {Binding Property, Mode=TwoWay} 来创建所谓的双向绑定。这将允许视图在 ViewModel 上设置属性。例如,如果您将“IsChecked={Binding IsToggled}”绑定更改为双向绑定,那么如果控件将其设置为 true,则 ViewModel 的 IsToggled 属性将设置为 true。这就是你要找的东西吗?
  • 这里有一个关于双向绑定的更多细节的问题:stackoverflow.com/questions/320028/two-way-binding-in-wpf
  • 继续 IsToggled 示例,如果您想要更新其他属性(例如文本)以响应 IsToggled 的更改,您可以从 IsToggled 的设置器中执行此操作。当其他属性发生变化时,View 将通过 INotifyPropertyChanged 进行更新。
  • 总结一下:这是我一直在寻找的答案,我通过添加一个公开 Observable Collection 中包含的各个 Observable 对象的方法来混合这两种方法(使用第二个上面的示例)在可观察集合的 set 方法中调用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-22
  • 2017-09-28
  • 1970-01-01
  • 2017-07-12
  • 1970-01-01
  • 1970-01-01
  • 2017-09-07
相关资源
最近更新 更多