绑定 - 为ListView列动态选择数据

时间:2014-01-22 21:17:49

标签: c# wpf xaml mvvm

以下是这种情况:我有一个对象列表,每个对象都带有一个ID号。我正在尝试根据对象的ID号在listview的列中设置一个值:

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

然而,这感觉有点像黑客而不是最佳实践,那么还有另一种更好的方法来完成同样的事情吗?

编辑:

这是ObjectList中对象的片段,就像我现在所拥有的那样。

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

2 个答案:

答案 0 :(得分:2)

我会从对象中删除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()调用添加到return,否则它给了我一个绑定错误,textblock需要一个字符串值(感谢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 :(得分:0)

您只需要在ObjectInObjectList课程的属性上实施INotifyPropertyChanged Interface即可。特别是,当PropertyOfAnItemInAList属性发生更改时,您需要告诉接口CurrentID属性已更改:

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

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