【问题标题】:Binding - dynamically choosing your data for a ListView column绑定 - 为 ListView 列动态选择数据
【发布时间】:2014-02-13 04:10:49
【问题描述】:

情况如下:我有一个对象列表,每个对象都有一个 ID 号。我正在尝试根据对象的 ID 号在列表视图的列中设置一个值:

<ListView     Name="Listview1"
              Itemsource="{Binding ObjectList}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Header1"    DisplayMemberBinding="{Binding subObject.property}"/>
            <GridViewColumn Header="Header2"    DisplayMemberBinding="{Binding PropertyOfAnItemInAList"/>
        </GridView>
    </ListView.View>
</ListView>

ObjectList 是 ViewModel 中的一个属性,向 ListView 证明一个 ObservableCollection 进行处理。 Header1 和 Header2 绑定到 ObservableCollection 中名为“ObjectList”的项目中的属性。

这一切都适用于 Header1。问题是 Header2 需要从驻留在 ObservableCollection 的每个元素内的列表中选择一个项目,并根据 ObjectList 中引用项目的另一个属性显示它。

那么我该怎么做呢?

我已经设法通过在 ObjectList 中的对象内设置一个名为“currentSelection”的变量来使其工作,然后当绑定从 ItemSource 遍历 ObjectList 以生成 ListView 时,该变量被设置:

public ObservableCollection<theObject> ObjectList {

    get {
        foreach (theObject obj in sourceCollection) {

           obj.CurrentID = MyID;
        }

        return new ObservableCollection<theObject>sourceCollection // <-- secondary question:  Is this the best way to send an observableCollection to a View???
    }
}

但是,这感觉有点像 hack,而不是最佳实践,那么还有其他更好的方法来完成同样的事情吗?

编辑:

这是 ObjectList 中对象的 sn-p,就像我现在拥有的一样。

public class ObjectInObjectList {

    /* constructor and various properties snipped to save space */

    private subObject subObj;

    public int CurrentID {get; set;}

    public SubObject {

         get { return subObject; } // etc...
    }

    private SortedList<int,int> valuesIWantInSecondColumn

    Public int PropertyOfAnItemInAList {

         return valuesIWantInSecondColumn[currentID];
    }

【问题讨论】:

  • 我不确定我是否理解您的问题。您是否只是在寻找将 MyID 放入带有 Header1 标题的列的最佳方法?
  • 我重读了它,现在认为您正在尝试将“Header2”列绑定到不同的属性,具体取决于在另一个控件中选择了哪个项目,并且您通过使用带有开关的另一个属性(CurrentID)来完成此操作根据情况返回特定属性的语句。这是准确的吗?能否展示一下theObject的相关代码?
  • 李 - 这非常正确。我将在问题的编辑中添加相关代码。

标签: c# wpf xaml mvvm


【解决方案1】:

我会从对象中删除 CurrentID 属性。我不想在我的域对象中有 UI 属性。我认为最好的解决方案是对该列使用多重绑定,并从 ViewModel 中为其提供 SortedList 和您的 MyID 值,使用转换器从 sortedlist 中返回所选项目。像这样的东西(假设列出的组合框也是如此):

    <ComboBox Grid.Column="0" ItemsSource="{Binding Ids}" SelectedItem="{Binding MyID}" />
    <ListView Name="Listview1" Grid.Column="1" ItemsSource="{Binding ObjectList}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Header1" DisplayMemberBinding="{Binding subObject.property}"/>
                <GridViewColumn Header="Header2" >
                    <GridViewColumn.DisplayMemberBinding>
                        <MultiBinding Converter="{StaticResource IDictionarySelector}">
                            <Binding Path="PropertyOfAnItemInAList" />
                            <Binding Path="DataContext.MyID" RelativeSource="{RelativeSource AncestorType={x:Type Window}}" />
                        </MultiBinding>
                    </GridViewColumn.DisplayMemberBinding>
                </GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>

我测试了这段代码,必须将 ToString() 调用添加到返回中,否则它会给我一个绑定错误,即文本块需要一个字符串值(感谢 Snoop):

public class IDictionarySelector : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (values != null && values.Length == 2)
        {
            IDictionary idictionary = values[0] as IDictionary;
            int? key = values[1] as int?;

            if ((idictionary != null) && (key != null) && (idictionary.Contains(key)))
            {
                return idictionary[key].ToString();
            }
        }

        return null;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

【讨论】:

  • 谢谢。 (+1)我会试试这个。我还将在下面查看 Sheridan 的评论,看看它是否值得纳入。我认为 Sheridan 的观点也很好。如果成功,我会将其标记为答案。
【解决方案2】:

您只需要在您的ObjectInObjectList 类中的属性上实现INotifyPropertyChanged Interface。特别是当CurrentID属性发生变化时,需要告诉接口PropertyOfAnItemInAList属性发生了变化:

public int CurrentID
{
   get { return currentID; }
   set 
   {
       currentID = value;
       NotifyPropertyChanged("CurrentID");
       NotifyPropertyChanged("PropertyOfAnItemInAList");
   }
}

每次更改 CurrentID 属性时,此通知都会更新 UI 中的 PropertyOfAnItemInAList 属性,因此您不需要任何特殊类型的 Binding

【讨论】:

  • 我明白你的意思,但这不是我要找的。填充 ListView 的对象位于一个列表中,每个对象都有一个元素的子列表,必须根据父元素的属性进行选择。 ...
  • ...可以这样想:一家诊所的两组记录。第一组记录是医生,每个医生都提供专门的服务。第二组是病人。每个医生有多个病人,每个病人可以有多个医生。假设我们希望列表视图显示医生的患者,以及每个患者就诊的次数。因此,在这种情况下,我们在对象内的列表是患者的 ID 号,作为键的整数,值是他们访问过的次数。
  • 你只是让你的生活变得如此复杂。如果您使用分层数据对业务规则进行建模,它将大大简化您的 UI。我的意思是有一个Doctor 对象和一个Patient 对象... Doctor 将有一个ObservableCollection&lt;Patient&gt; 和一个Patient 将有一个ObservableCollection&lt;Doctor&gt; 等等。使用 WPF 和 MVVM,在 UI* 中提供所有您需要的数据总是最容易的。
猜你喜欢
  • 1970-01-01
  • 2010-09-18
  • 2020-02-27
  • 2012-12-22
  • 1970-01-01
  • 2019-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多