使用WPF进行数据绑定-更新Input上的CollectionViewSource

问题描述

|| 我已经按照此MSDN Walktrough的说明创建了一个示例项目。我对示例进行了一些更改,并创建了两个附加的TextBox控件和一个按钮。 这就是它的样子: 我已经使用代码优先方法和DbContext的派生类作为代码生成项创建了一个简单的模型。 之后,我使用了创建的数据源: \“名称\”-文本框为只读。我想允许用户在按下\“ Search \”-按钮时输入ID并进行搜索。因此,如果可以找到指定的ID,则应更新\“ Name \”-TextBox。我不太在乎DataGrid,因为我的实际代码中不需要它们。 我不知道如何更新CollectionViewSource并验证输入,因为CollectionViewSource.View.CurrentItem属性是只读的。 编辑:那是我的(几乎完全由设计师生成的)代码
<Window x:Class=\"WpfApplication1.MainWindow\"
        xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"
        xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"
        Title=\"MainWindow\" Height=\"350\" Width=\"525\" mc:Ignorable=\"d\"
        xmlns:d=\"http://schemas.microsoft.com/expression/blend/2008\" 
        xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\"
        xmlns:my=\"clr-namespace:SchoolModel;assembly=SchoolModel\" 
        Loaded=\"Window_Loaded\">

    <Window.Resources>
        <CollectionViewSource x:Key=\"departmentViewSource\" d:DesignSource=\"{d:DesignInstance my:Department,CreateList=True}\" />
    </Window.Resources>

    <Grid>
        <Grid.RowDeFinitions>
            <RowDeFinition/>
            <RowDeFinition/>
        </Grid.RowDeFinitions>

        <Grid DataContext=\"{StaticResource departmentViewSource}\" Name=\"grid1\">
            <Grid.ColumnDeFinitions>
                <ColumnDeFinition Width=\"Auto\" />
                <ColumnDeFinition Width=\"Auto\" />
            </Grid.ColumnDeFinitions>
            <Grid.RowDeFinitions>
                <RowDeFinition Height=\"Auto\" />
            </Grid.RowDeFinitions>
            <Label Content=\"Department ID:\" Grid.Column=\"0\" Grid.Row=\"0\" HorizontalAlignment=\"Left\" Margin=\"3\" VerticalAlignment=\"Center\" />
            <TextBox Grid.Column=\"1\" Grid.Row=\"0\" Height=\"23\" HorizontalAlignment=\"Left\" Margin=\"3\" Name=\"departmentIDTextBox\" Text=\"{Binding Path=DepartmentID,Mode=TwoWay,ValidatesOnExceptions=true,NotifyOnValidationError=true}\" VerticalAlignment=\"Center\" Width=\"120\" />
        </Grid>
        <Grid Grid.Row=\"1\" DataContext=\"{StaticResource departmentViewSource}\" Name=\"grid2\">
            <Grid.ColumnDeFinitions>
                <ColumnDeFinition Width=\"Auto\" />
                <ColumnDeFinition Width=\"Auto\" />
            </Grid.ColumnDeFinitions>
            <Grid.RowDeFinitions>
                <RowDeFinition Height=\"Auto\" />
            </Grid.RowDeFinitions>
            <Label Content=\"Name:\" Grid.Column=\"0\" Grid.Row=\"0\" HorizontalAlignment=\"Left\" Margin=\"3\" VerticalAlignment=\"Center\" />
            <TextBox Grid.Column=\"1\" Grid.Row=\"0\" Height=\"23\" HorizontalAlignment=\"Left\" Margin=\"3\" Name=\"nameTextBox\" Text=\"{Binding Path=Name,NotifyOnValidationError=true}\" VerticalAlignment=\"Center\" Width=\"120\" />
        </Grid>
    </Grid>
</Window>


public partial class MainWindow : Window
{
    private SchoolEntities _context = new SchoolEntities(@\"data source=localhost\\MSsql2008R2;database=SchoolModel;integrated security=True;MultipleActiveResultSets=True\");
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender,RoutedEventArgs e)
    {
        System.Windows.Data.CollectionViewSource departmentViewSource =
            ((System.Windows.Data.CollectionViewSource)(this.FindResource(\"departmentViewSource\")));

        // Load is an extension method on IQueryable,defined in the System.Data.Entity namespace.
        // This method enumerates the results of the query,much like ToList but without creating a list. 
        // When used with Linq to Entities this method creates the entity instances and adds to the context.
        _context.Departments.Load(); // Load is defined in the System.Data.Entity namespace.      

        // After the data is loaded call the DbSet<T>.Local property to use the DbSet<T> as a binding source. 
        departmentViewSource.source = _context.Departments.Local;

        var src = _context.Departments.Local;
        ICollectionView colelctionView = CollectionViewSource.Getdefaultview(src);
        colelctionView.Filter = new Predicate<object>(i => (i as Department).DepartmentID.ToString() == departmentIDTextBox.Text);
    }
}
    

解决方法

Free ICollectionView公开了以下方法来设置当前项目: MoveCurrentToFirst MoveCurrentToLast MoveCurrentToNext MoveCurrentToPrevious MoveCurrentTo(对象值) 我通常会发现最后一种方法对于要使用选定项目的生产代码最有用
    public Department SelectedItem
    {
        get { return _collectionView.CurrentItem as Department; }
        set { _collectionView.MoveCurrentTo(value); }
    }
它还公开了CurrentChanged事件,您可以使用该事件来设置处理程序,在该事件中,您可以执行任何需要的操作(包括验证)来对当前更改的项目做出反应。
// retrieve the ICollectionView associated with the ObservableCollection
_collectionView = CollectionViewSource.GetDefaultView(src);
if (_collectionView == null) throw new NullReferenceException(\"_collectionView\");

//listen to the CurrentChanged event to be notified when the selection changes
_collectionView.CurrentChanged += OnCollectionViewCurrentChanged;

private void OnCollectionViewCurrentChanged(object sender,EventArgs e) {
    // whatever
}
我可以说更多有关过滤的信息,但是我想您只是想在此处尝试一些示例代码,而对如何设置CurrentItem以及如何对其进行处理感到困惑。希望这会给您一些有关如何执行此操作的想法,但如有需要,可以随时询问更多问题。 干杯, 贝里     ,您的SearchTextBox应该绑定到ViewModel中的SearchText字段,而不是CurrentItem的名称 您的ViewModel应该看起来像:
ObservableCollection<Courses> { get; set; }
ObservableCollection<Departments> { get; set; }

string SearchText { get; set; }
ICommand SearchCommand { get; }