将列表框绑定到observablecollection

时间:2017-04-11 20:19:19

标签: c# wpf xaml

我需要一些帮助才能将ObservableCollection正确绑定到xaml。我可以正确绑定数据,但是当数据发生变化时,更改并未反映在屏幕上。我已经阅读了相关的博客并且似乎已经理解了,但是当我尝试将我所知道的内容应用到我自己的样本中时,它并没有像我想象的那样有效。

我有2个水果和水果类,其中水果是可观察到的水果收集,实现了INotifyPropertyChanged

namespace TestCommand.Models
{
    public class Fruit:INotifyPropertyChanged
    {
        private string _fruitname;
        public string FruitName
        { get
            {
                return _fruitname;
            }
            set
            {
                if (_fruitname!=value)
                {
                    _fruitname = value;
                    OnPropertyChanged("FruitName");
                }
            }
        }

        private string _fruitcolor;
        public string FruitColor
        {
            get
            {
                return _fruitcolor;
            }
            set
            {
                if (_fruitcolor != value)
                {
                    _fruitcolor = value;
                    OnPropertyChanged("FruitColor");
                }
            }
        }

        private bool _selected;
        public bool bSelected
        {
            get
            {
                return _selected;
            }
            set
            {
                if (_selected != value)
                {
                    _selected = value;
                    OnPropertyChanged("bSelected");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string name)
        {
            if (PropertyChanged!=null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

    namespace TestCommand.Models
    {
        public class Fruits
        {
            private static ObservableCollection<Fruit> _fruitList;
            public static void Add(string f, string c)
            {
                _fruitList.Add(new Fruit
                {
                    FruitName = f,
                    FruitColor = c,
                    bSelected = false
                });
            }
            static Fruits()
            {
                _fruitList = new ObservableCollection<Fruit>();
                _fruitList.Add(new Fruit
                {
                    FruitName = "Mango",
                    FruitColor = "Yellow",
                    bSelected = false
                });
                _fruitList.Add(new Fruit
                {
                    FruitName = "Mango",
                    FruitColor = "Yellow",
                    bSelected = false
                });
                _fruitList.Add(new Fruit
                {
                    FruitName = "Water Melon",
                    FruitColor = "Green",
                    bSelected = false
                });
                _fruitList.Add(new Fruit
                {
                    FruitName = "Apple",
                    FruitColor = "Red",
                    bSelected = false
                });
                _fruitList.Add(new Fruit
                {
                    FruitName = "Banana",
                    FruitColor = "Yellow",
                    bSelected = false
                });
                _fruitList.Add(new Fruit
                {
                    FruitName = "Orange",
                    FruitColor = "Orange",
                    bSelected = false
                });
            }
            public static ObservableCollection<Fruit> getAllFruit(bool bSelected = false)
            {
                var result = (bSelected ?
                                            _fruitList.Where(x => x.bSelected = true).ToList<Fruit>()
                                            : _fruitList.ToList<Fruit>());
                return new ObservableCollection<Fruit>(result);
            }
        }
    }

我的xaml:

<Window x:Class="TestCommand.MainWindow"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:local="clr-namespace:TestCommand"
                xmlns:MyCommands='clr-namespace:TestCommand.Commands'
                mc:Ignorable="d"
                Title="MainWindow"
                Height="350"
                Width="525">
    <StackPanel Orientation='Vertical' Margin='10'>
        <ListBox x:Name='MyList' ItemTemplate='{StaticResource FruitTemp}'>
        </ListBox>
        <Button x:Name='AddFruit'
                        Height='auto'
                        Width='auto'
                        Content='Add New Fruit 2'
                        Margin='0,10,0,0'
                        Command='{x:Static MyCommands:TestButtonCommand.AddFruit}'>
            <Button.CommandBindings>
                <CommandBinding Command='{x:Static MyCommands:TestButtonCommand.AddFruit}'
                                                Executed='CommandBinding_Executed'
                                                CanExecute='CommandBinding_CanExecute' />
            </Button.CommandBindings>
        </Button>
    </StackPanel>
</Window>

和代码背后:

namespace TestCommand
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            MyList.ItemsSource = Fruits.getAllFruit();
        }

        private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Fruits.Add("Durian", "Green");
        }

        private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }
    }
}

我的ItemTemplate

<Application x:Class="TestCommand.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:TestCommand"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
            <DataTemplate x:Key='FruitTemp'>
                <StackPanel Orientation='Horizontal'
                                        Margin='5'>
                    <TextBlock x:Name='tbName'
                                         Text='{Binding FruitName}' 
                                         Margin='10,0,0,0'
                                         Width='100'/>
                    <TextBlock x:Name='tbColor'
                                     Text='{Binding FruitColor}'
                                     Margin='10,0,0,0'
                                     Width='100' />
                    <!--<CheckBox x:Name='cbSelected'
                                        Content='Selected'
                                        Checked='{Binding bSelected}' />-->
                </StackPanel>
            </DataTemplate>
    </Application.Resources>
</Application>

当我点击按钮时,我看到项目已添加到集合中,但集合未在列表中刷新。我必须没有正确地绑定集合或者可能错过了一些东西,因为我对wpf很新。

非常感谢你帮我指出我的忽视。

1 个答案:

答案 0 :(得分:2)

此方法创建一个新的ObservableCollection并返回它。您将其分配给MyList.ItemsSource(不是绑定,这只是一项任务),然后您将项目添加到其他地方的其他ObservableCollection

MyList.ItemsSource = Fruits.getAllFruit();

...

public static ObservableCollection<Fruit> getAllFruit(bool bSelected = false)
{
    var result = (bSelected ? _fruitList.Where(x => x.bSelected = true).ToList<Fruit>()
        : _fruitList.ToList<Fruit>());
    return new ObservableCollection<Fruit>(result);
}

当然,您在_fruitList的{​​{1}}的副本中看不到任何新项目。

ListBox必须具有与您添加对象相同的实际集合对象。

ListBox

糟糕,没有过滤。

这仍然不是正确的方法。编写一个viewmodel,其中包含一个返回public static ObservableCollection<Fruit> getAllFruit(bool bSelected = false) { return _fruitList; } 的公共Fruits属性,并在XAML中使用ObservableCollection<Fruit>进行过滤。如果需要,我们可以完成所有这些工作。您已经知道如何实施CollectionViewSource,以便您继续前进。

更新

我快速重写了Fruits应用程序作为MVVM的东西。通常我会使用委托命令将AddNewFruit命令作为viewmodel的属性,但我不想写一个委托命令类并将其粘贴进去。但是这里的确如此。

ViewModels.cs

INotifyPropertyChanged

的App.xaml

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows.Media;

namespace Fruits.ViewModels
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }

    public class Fruit : ViewModelBase
    {
        public Fruit()
        {
        }

        public Fruit(string name, String clrString)
        {
            FruitName = name;
            //  Parse colors like so: (Color)ColorConverter.ConvertFromString(clrString);
            FruitColor = clrString;
        }

        public Fruit(string name, Color clr)
        {
            FruitName = name;
            FruitColor = clr.ToString();
        }

        private string _fruitname;
        public string FruitName
        {
            get
            {
                return _fruitname;
            }
            set
            {
                if (_fruitname != value)
                {
                    _fruitname = value;
                    OnPropertyChanged("FruitName");
                }
            }
        }

        private String _fruitcolor;
        public String FruitColor
        {
            get
            {
                return _fruitcolor;
            }
            set
            {
                if (_fruitcolor != value)
                {
                    _fruitcolor = value;
                    OnPropertyChanged("FruitColor");
                }
            }
        }

        private bool _isSelected = true;
        //  NOTE: I renamed this property
        public bool IsSelected
        {
            get
            {
                return _isSelected;
            }
            set
            {
                if (_isSelected != value)
                {
                    _isSelected = value;
                    OnPropertyChanged("IsSelected");
                }
            }
        }
    }

    #region MainViewModel Class
    public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            Fruits = new ObservableCollection<Fruit>();

        }

        #region ShowSelectedFruitOnly Property
        private bool _showSelectedFruitOnly = true;
        public bool ShowSelectedFruitOnly
        {
            get { return _showSelectedFruitOnly; }
            set
            {
                if (value != _showSelectedFruitOnly)
                {
                    _showSelectedFruitOnly = value;
                    FruitsView.Refresh();
                    OnPropertyChanged("ShowSelectedFruitOnly");
                }
            }
        }
        #endregion ShowSelectedFruitOnly Property

        #region Add Methods
        public void AddNewFruit()
        {
            Fruits.Add(new Fruit(NewFruitName, NewFruitColor));

            NewFruitName = "";
            NewFruitColor = "";
        }

        public void AddNewFruit(string name, string color)
        {
            Fruits.Add(new Fruit(name, color));
        }

        public void AddNewFruit(string name, Color color)
        {
            Fruits.Add(new Fruit(name, color));
        }
        #endregion Add Methods

        #region NewFruitName Property
        private String _newFruitName = default(String);
        public String NewFruitName
        {
            get { return _newFruitName; }
            set
            {
                if (value != _newFruitName)
                {
                    _newFruitName = value;
                    OnPropertyChanged("NewFruitName");
                }
            }
        }
        #endregion NewFruitName Property

        #region NewFruitColor Property
        private String _newFruitColor = default(String);
        public String NewFruitColor
        {
            get { return _newFruitColor; }
            set
            {
                if (value != _newFruitColor)
                {
                    _newFruitColor = value;
                    OnPropertyChanged("NewFruitColor");
                }
            }
        }
        #endregion NewFruitColor Property

        public ICollectionView FruitsView { get; private set; }

        #region Fruits Property
        private ObservableCollection<Fruit> _fruits;
        public ObservableCollection<Fruit> Fruits
        {
            get { return _fruits; }
            private set
            {
                if (value != _fruits)
                {
                    _fruits = value;

                    FruitsView = CollectionViewSource.GetDefaultView(Fruits);

                    FruitsView.Filter = FruitFilterPredicate;
                    FruitsView.Refresh();

                    OnPropertyChanged("Fruits");
                }
            }
        }

        protected bool FruitFilterPredicate(Object o)
        {
            if (ShowSelectedFruitOnly)
            {
                return (o as Fruit).IsSelected;
            }

            return true;
        }
        #endregion Fruits Property
    }
    #endregion MainViewModel Class
}

MainWindow.xaml

<Application 
    x:Class="Fruits.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Fruits"
    StartupUri="MainWindow.xaml"
    >
    <Application.Resources>
        <Style x:Key="ColorSwatch" TargetType="ContentControl">
            <Setter Property="Width" Value="24" />
            <Setter Property="Height" Value="24" />
            <Setter Property="IsTabStop" Value="false" />
            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <Rectangle
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            Stroke="Gray"
                            StrokeThickness="1"
                            >
                            <Rectangle.Fill>
                                <SolidColorBrush Color="{Binding}" />
                            </Rectangle.Fill>
                        </Rectangle>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <DataTemplate x:Key='FruitTemp'>
            <StackPanel 
                Orientation='Horizontal'
                Margin='5'>
                <TextBlock 
                    x:Name='tbName'
                    Text='{Binding FruitName}' 
                    Margin='10,0,0,0'
                    Width='100'/>
                <TextBlock 
                    x:Name='tbColor'
                    Text='{Binding FruitColor}'
                    Margin='10,0,0,0'
                    Width='100' />
                <ContentControl
                    Width="16"
                    Height="16"
                    Style="{StaticResource ColorSwatch}"
                    Content="{Binding FruitColor}"
                    />
                <!-- The problem here was you were trying to bind Checked, an event, 
                instead if IsChecked, a bool? property. 
                -->
                <CheckBox 
                    x:Name='cbSelected'
                    Content='Selected'
                    Margin='10,0,0,0'
                    IsChecked='{Binding IsSelected}' 
                    />
            </StackPanel>
        </DataTemplate>
    </Application.Resources>
</Application>

MainWindow.xaml.cs

<Window 
    x:Class="Fruits.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Fruits"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525"
    >
    <Window.Resources>
        <RoutedCommand
            x:Key="AddFruit"
            />
    </Window.Resources>
    <Window.CommandBindings>
        <CommandBinding 
            Command='{StaticResource AddFruit}'
            Executed='AddFruitCommandBinding_Executed'
            CanExecute='AddFruitCommandBinding_CanExecute' 
            />
    </Window.CommandBindings>
    <Grid>
        <StackPanel Orientation='Vertical' Margin='10'>
            <CheckBox IsChecked="{Binding ShowSelectedFruitOnly}">Selected Fruit Only</CheckBox>
            <ListBox 
                x:Name='MyList' 
                ItemsSource="{Binding FruitsView}"
                ItemTemplate='{StaticResource FruitTemp}'
                />
            <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                <Label Width="100">New Name:</Label>
                <TextBox Width="200" Text="{Binding NewFruitName}" />
            </StackPanel>
            <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                <Label Width="100">New Color:</Label>
                <TextBox Width="200" Text="{Binding NewFruitColor, UpdateSourceTrigger=PropertyChanged}" />

                <ContentControl
                    Style="{StaticResource ColorSwatch}"
                    Margin="2" 
                    VerticalAlignment="Center" 
                    Content="{Binding NewFruitColor}"
                    />
            </StackPanel>
            <Button 
                x:Name='AddFruit'
                Height='auto'
                Width='auto'
                Content='Add New Fruit 2'
                Margin='0,10,0,0'
                Command='{StaticResource AddFruit}'
                />
        </StackPanel>
    </Grid>
</Window>

截图:

enter image description here

标准HTML颜色名称(see System.Windows.Media.Colors for WPF predefined color constants)适用于颜色,因此using System; using System.Windows; using System.Windows.Input; using Fruits.ViewModels; namespace Fruits { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new MainViewModel(); ViewModel.AddNewFruit("Jackfruit", "Yellow"); ViewModel.AddNewFruit("Watermelon", "ForestGreen"); ViewModel.AddNewFruit("Apple", "Red"); ViewModel.AddNewFruit("Banana", "Yellow"); ViewModel.AddNewFruit("Orange", "DeepSkyBlue"); ViewModel.Fruits[0].IsSelected = false; ViewModel.Fruits[1].IsSelected = false; ViewModel.FruitsView.Refresh(); } public MainViewModel ViewModel { get { return DataContext as MainViewModel; } } private void AddFruitCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) { ViewModel.AddNewFruit(); } private void AddFruitCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = ViewModel != null && !String.IsNullOrWhiteSpace(ViewModel.NewFruitName) && !String.IsNullOrWhiteSpace(ViewModel.NewFruitColor) ; } } } #RRGGBB十六种颜色也适用。