9

我有一个列表视图,我xaml用这样的项目填充:

List<DataLayer.Models.Dictionary> dicts = DataLayer.Manager.getDictionaries();

if (dicts != null)
{
    foreach (DataLayer.Models.Dictionary dict in dicts)
    {
         this.itemListView.Items.Add(dict);
    }
}

我的DataLayer.Models.Dictionary对象有一个isSelected属性以及 aName和 a SubName

Name 和 SubName 在模板中工作正常,但是当用户单击一个项目时,我怎样才能让项目被选中并更新?

谢谢!

编辑:

我的 xaml 现在看起来像这样,但该项目仍未选中

    <ListView
        x:Name="itemListView"
        TabIndex="1"
        Grid.Row="1"
        Margin="0,60,0,0"
        Padding="0,0,0,0"
        IsSwipeEnabled="False"
        ScrollViewer.VerticalScrollBarVisibility="Hidden"
        SelectionChanged="itemListView_SelectionChanged_1"
        SelectionMode="Multiple"
        FontFamily="Global User Interface">
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="IsSelected" Value="{Binding Source=Selected,Mode=TwoWay}"/>
            </Style>
        </ListView.ItemContainerStyle>
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid Margin="6">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <StackPanel Grid.Column="0" Margin="0,0,0,0">
                        <TextBlock Text="{Binding Name}"/>
                        <TextBlock Text="{Binding SubName}" Style="{StaticResource CaptionTextStyle}" TextWrapping="Wrap"/>
                    </StackPanel>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
4

1 回答 1

8

[编辑] 刚刚注意到这个问题实际上并没有标记 WPF;但我希望它仍然适用。

WPF 本质上是 MVVM。直接在代码后面操作控件通常不是一个好主意。因此建议创建一个名为 ViewModel 的“视图友好”模型;见这里。此外,要使绑定发挥作用,在不断变化的环境中,您必须通知属性和/或集合的更改,以便可以更新控件。

首先,您有一个字典集合,因此您创建了这个集合,以便它可以通知更改;ObservableCollection可以做到这一点。作为一般经验法则,WPF 使用的任何集合都应该只使用 ObservableCollection,和/或从它派生。

所以这是竞争工作示例:

请记住,我正在使用FODY来注入我的 PropertyChanged raisers;见手动完成

public class Dict : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string Name { get; set; }
    public string SubName { get; set; }
    public bool Selected { get; set; }
}

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection<Dict> Dictionaries { get; set; }

    public ViewModel()
    {
        Dictionaries = new ObservableCollection<Dict>()
        {
            new Dict()
                {
                    Name = "English",
                    SubName = "en",
                    Selected = false,
                },

                new Dict()
                {
                    Name = "English-British",
                    SubName = "en-uk",
                    Selected = true
                },

                new Dict()
                {
                    Name = "French",
                    SubName = "fr",
                    Selected = true
                }
        };

        Dictionaries.CollectionChanged += DictionariesCollectionChanged;
    }

    private void DictionariesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch(e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                foreach(var dict in e.NewItems.Cast<Dict>())
                    dict.PropertyChanged += DictionaryChanged;
                break;
            case NotifyCollectionChangedAction.Remove:
                foreach (var dict in e.OldItems.Cast<Dict>())
                    dict.PropertyChanged -= DictionaryChanged;
                break;
        }
    }

    private void DictionaryChanged(object sender, PropertyChangedEventArgs e)
    {
        Dict dictionary = (Dict)sender;

        //handle a change in Dictionary
    }
}

有了它,您可以随时添加或删除对象,尽管这里我只是在构造函数中初始化它们。

然后你会在你的窗口或控件中有这个。我已经包含了命名空间以使其更加独立;但这适用于 WPF 命名空间。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:local="clr-namespace:WpfApplication1">

    <Window.Resources>
        <local:ViewModel x:Key="viewmodel"/>
    </Window.Resources>

    <ListView
        x:Name="itemListView"
        DataContext="{StaticResource ResourceKey=viewmodel}"
        ItemsSource="{Binding Path=Dictionaries}"
        SelectionMode="Multiple">

        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="IsSelected" Value="{Binding Path=Selected, Mode=TwoWay}"/>
            </Style>
        </ListView.ItemContainerStyle>

        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid Margin="6">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <StackPanel Grid.Column="0" Margin="0,0,0,0">
                        <TextBlock Text="{Binding Name}"/>
                        <TextBlock Text="{Binding SubName}" TextWrapping="Wrap"/>
                    </StackPanel>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Window>

如果您不为您的集合使用 ObservableCollection,然后在 WPF 加载开始向其中添加元素,它将永远不会通知绑定管理器应该更新 ListView。

上面的启动:

开始时,注意力不集中

你可以很容易地看到底层的字典集合正在被改变(即不仅仅是 ListView),通过覆盖选择的返回值:

public bool Selected { get { return true; } set {/* do nothing*/ }}

这意味着始终选择所有内容,即使您尝试在视图中取消选择它。它总是看起来像这样:

始终选中

样式是一个不同的问题,如果没有焦点,列表看起来会有所不同。看这里

现在可以在代码隐藏中对选择更改做出反应,但这会将逻辑与视图混合。

[编辑] 更新以包括检测任何字典中的更改的能力(包括选择更改时)

您可以研究一下以简化它

希望这可以帮助。

于 2013-03-02T09:50:16.773 回答