从viewmodel刷新视图上的datagrid

时间:2010-03-18 19:15:29

标签: wpf datagrid mvvm binding viewmodel

我在一个绑定到viewmodel的视图上有一个datagrid。当我初始化视图时,数据网格将填充来自viewmodel(ObservableCollection)的数据。但是,当我尝试对数据进行搜索时,数据网格不会从viewmodel刷新。当我断开我的viewmodel中的代码时,我可以看到ObservableCollection中的结果已经根据我的搜索发生了变化,但不知怎的,它没有被传递回视图。这是我的视图和视图模型(BTW,我正在使用VS2010 RTM):

namespace Attendance.ViewModels
{
    public class EmployeeSelectViewModel : ViewModel, INotifyPropertyChanged
    {
        #region Entity list and constructor
    public EmployeeSelectViewModel()
    {
        {
            Initialize();
        }
    }

    private void Initialize()
    {
        if (employeeRpository == null)
            employeeRpository = new EmployeeRepository();

        ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployees(true));
    }

    private EmployeeRepository employeeRpository;

    private ObservableCollection<EmployeeDto> listOfEmployees;
    public ObservableCollection<EmployeeDto> ListOfEmployees
    {
        get { return listOfEmployees; }
        set
        {
            if (listOfEmployees != value)
            {
                listOfEmployees = value;
                NotifyPropertyChanged("ListOfEmployee");
            }
        }
    }

    private EmployeeDto selectedEmployee;
    public EmployeeDto SelectedEmployee
    {
        get { return selectedEmployee; }
        set
        {
            if (selectedEmployee != value)
            {
                selectedEmployee = value;
                NotifyPropertyChanged("SelectedEmployee");
            }
        }
    }

    #endregion

    #region UI control references

    /// <summary>
    /// search text property
    /// </summary>
    private string searchText;
    public string SearchText
    {
        get { return searchText; }
        set
        {
            if (searchText != value)
            {
                searchText = value;
                NotifyPropertyChanged("SearchText");
            }
        }
    }

    public string Location { get; set; }

    #endregion

    #region Relay Commands

    /// <summary>
    /// new command
    /// </summary>
    private ViewCommand newCommand;
    public ViewCommand NewCommand
    {
        get
        {
            if (newCommand == null)
                newCommand = new ViewCommand(param => this.NewEmployee());
            return newCommand;
        }
    }
    private void NewEmployee()
    {
        NavigationActions.NewEmployeeView();
    }

    /// <summary>
    /// edit command
    /// </summary>
    private ViewCommand editCommand;
    public ViewCommand EditCommand
    {
        get
        {
            if (editCommand == null)
            {
                editCommand = new ViewCommand(param => this.EditEmployee());
            }
            return editCommand;
        }
    }

    private void EditEmployee()
    {
        NavigationActions.OpenEmployeeView(SelectedEmployee);
    }

    /// <summary>
    /// save command
    /// </summary>
    private ViewCommand saveCommand;
    public ViewCommand SaveCommand
    {
        get
        {
            if (saveCommand == null)
            {
                saveCommand = new ViewCommand(
                        param => this.SaveEmployee(),
                        param => this.CanSaveEmployee
                        );
            }
            return saveCommand;
        }
    }

    public void SaveEmployee()
    {
        employeeRpository.SaveChanges();
    }

    private bool CanSaveEmployee
    {
        get { return true; }
    }

    /// <summary>
    /// clear search command
    /// </summary>
    private ViewCommand clearSearchCommand;
    public ViewCommand ClearSearchCommand
    {
        get
        {
            if (clearSearchCommand == null)
                clearSearchCommand = new ViewCommand(param => this.ClearSearch());
            return clearSearchCommand;
        }
    }

    private void ClearSearch()
    {
        this.SearchText = string.Empty;
        ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployees(true));
    }

    /// <summary>
    /// search command
    /// </summary>
    private ViewCommand searchCommand;
    public ViewCommand SearchCommand
    {
        get
        {
            if (searchCommand == null)
                searchCommand = new ViewCommand(param => this.SearchEmployee());
            return searchCommand;
        }
    }

    private void SearchEmployee()
    {
        if (this.SearchText == string.Empty || this.SearchText == null)
        {
            NavigationActions.ShowError("Search Employees.", "Please enter your search text ...");
            return;
        }
        ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployeesByQuery(SearchText, Location));
    }

    /// <summary>
    /// exit command
    /// </summary>
    private ViewCommand exitCommand;
    public ViewCommand ExitCommand
    {
        get
        {
            if (exitCommand == null)
            {
                exitCommand = new ViewCommand(param => this.ExitWindow());
            }
            return exitCommand;
        }
    }

    private void ExitWindow()
    {
        NavigationActions.CloseCurrentView();
    }
    #endregion


    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    #endregion
    }
}

<Window x:Class="Attendance.Views.EmployeeSelectView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:Attendance.ViewModels"
    Title="Employee Maintenance" FocusManager.FocusedElement="{Binding ElementName=txtSearchCriteria}"
    Height="525" Width="800" WindowStartupLocation="CenterScreen" WindowState="Normal"
    WindowStyle="SingleBorderWindow" Icon="Images/gb_icon.png">
<Window.DataContext>
    <vm:EmployeeSelectViewModel />
</Window.DataContext>
<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Themes/DataGrid.Generic.xaml" />
        </ResourceDictionary.MergedDictionaries>
        <!--xml data start-->
        <XmlDataProvider x:Key="LocationData" XPath="LocationList/LocationItem" Source="XMLData/Location.xml"/>
        <!--xml data end-->
    </ResourceDictionary>
</Window.Resources>
<Grid Width="775">
    <DockPanel HorizontalAlignment="Left" Width="770">
        <!-- TOOLBAR -->
        <DockPanel DockPanel.Dock="Top" MinHeight="30" Margin="5">
            <ToolBar FontWeight="Bold">
                <!-- NEW -->
                <Button Name="btnNew" Command="{Binding Path=NewCommand}">
                    <Button.ToolTip>
                        <StackPanel>
                            <Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
                                Create a new Customer
                            </Label>
                            <TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
                            Create a new customer in a new Window tab.
                            </TextBlock>
                            <Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
                            <StackPanel Orientation="Horizontal">
                                <Image Margin="2" Source="Images/new.png"/>
                                <Label>Press F1 for more help</Label>
                            </StackPanel>
                        </StackPanel>
                    </Button.ToolTip>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="Images/new.png" Width="22" Height="22" Margin="2"/>
                        <Label VerticalAlignment="Center">_New</Label>
                    </StackPanel>
                </Button>
                <!-- EDIT -->
                <Button Name="btnEdit" Command="{Binding Path=EditCommand}">
                    <Button.ToolTip>
                        <StackPanel>
                            <Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
                                Edit the current record
                            </Label>
                            <TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
                            Edit the current selected Customer.
                            </TextBlock>
                            <Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
                            <StackPanel Orientation="Horizontal">
                                <Image Margin="2" Source="Images/dialog-information.png"/>
                                <Label>Press F1 for more help</Label>
                            </StackPanel>
                        </StackPanel>
                    </Button.ToolTip>

                    <StackPanel Orientation="Horizontal">
                        <Image Source="Images/edit.png" Width="22" Height="22" Margin="2" />
                        <Label VerticalAlignment="Center">_Edit</Label>
                    </StackPanel>
                </Button>
                <!-- SEARCH -->
                <Separator />
                <TextBox Name="txtSearchCriteria" 
                    MinWidth="300" Margin="5"
                    BorderThickness="1" BorderBrush="LightGray"
                    FontWeight="Normal" Foreground="Gray" Text="{Binding Path=SearchText}">
                </TextBox>
                <Button Name="btnSearch" Command="{Binding Path=SearchCommand}">
                    <Button.ToolTip>
                        <StackPanel>
                            <Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
                                Search
                            </Label>
                            <TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
                            Search a specific Customer.
                            </TextBlock>
                            <Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
                            <StackPanel Orientation="Horizontal">
                                <Image Margin="2" Source="Images/find.png"/>
                                <Label>Press F1 for more help</Label>
                            </StackPanel>
                        </StackPanel>
                    </Button.ToolTip>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="Images/find.png" Width="22" Height="22" Margin="2" />
                        <Label VerticalAlignment="Center">_Find</Label>
                    </StackPanel>
                </Button>
                <Button Name="btnClearSearch" Command="{Binding Path=ClearSearchCommand}">
                    <Button.ToolTip>
                        <StackPanel>
                            <Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
                                Search
                            </Label>
                            <TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
                            Clear search results.
                            </TextBlock>
                            <Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
                            <StackPanel Orientation="Horizontal">
                                <Image Margin="2" Source="Images/find.png"/>
                                <Label>Press F1 for more help</Label>
                            </StackPanel>
                        </StackPanel>
                    </Button.ToolTip>
                    <StackPanel Orientation="Horizontal">
                        <Label VerticalAlignment="Center">_Clear Search</Label>
                    </StackPanel>
                </Button>
                <!-- EXIT -->
                <Separator />
                <Button Name="btnExit" Command="{Binding Path=ExitCommand}">
                    <Button.ToolTip>
                        <StackPanel>
                            <Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
                                Start the application
                            </Label>
                            <TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
                            Start the main application with the M-V-MV pattern.
                            </TextBlock>
                            <Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
                            <StackPanel Orientation="Horizontal">
                                <Image Margin="2" Source="Images/dialog-information.png"/>
                                <Label>Press F1 for more help</Label>
                            </StackPanel>
                        </StackPanel>
                    </Button.ToolTip>

                    <StackPanel Orientation="Horizontal">
                        <Image Source="Images/exit.png" Width="22" Height="22" Margin="2" />
                        <Label VerticalAlignment="Center">_Exit</Label>
                    </StackPanel>
                </Button>
            </ToolBar>
        </DockPanel>
        <!-- LIST -->
        <DockPanel DockPanel.Dock="Top" MinHeight="30" Margin="0,0,0,5">
            <Label>Location:</Label>
            <ComboBox Name="cboLocation" Grid.Column="1" Grid.Row="4" 
                                ItemsSource="{Binding Source={StaticResource LocationData}}"
                                DisplayMemberPath="location_text" SelectedValuePath="location_value" 
                                SelectedValue="{Binding Path=Location}" 
                                HorizontalAlignment="Left" Width="175" Margin="4" />
        </DockPanel>
        <DockPanel Margin="5">
            <DataGrid ItemsSource="{Binding Path=ListOfEmployees}" AutoGenerateColumns="False" IsReadOnly="True" 
                Name="dgEmployee" SelectionMode="Single" SelectionUnit="FullRow" CanUserResizeColumns="True" 
                SelectedItem="{Binding Path=SelectedEmployee}" GridLinesVisibility="Horizontal">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Employee ID" Width="SizeToCells"  MinWidth="125" Binding="{Binding EmployeeID}" />
                    <DataGridTextColumn Header="First Name" Width="SizeToCells"  MinWidth="200" Binding="{Binding FirstName}" />
                    <DataGridTextColumn Header="Last Name" Width="SizeToCells"  MinWidth="200" Binding="{Binding LastName}" />
                    <DataGridTextColumn Header="Location" Width="SizeToCells"  MinWidth="125" Binding="{Binding Location}" />
                    <DataGridCheckBoxColumn x:Name="Active" Header="Active" Binding="{Binding active}" MinWidth="75" />
                </DataGrid.Columns>
            </DataGrid>
        </DockPanel>
    </DockPanel>
</Grid>

4 个答案:

答案 0 :(得分:3)

这是我的解决方案:

<DataGrid Name="dgrid" ItemsSource="{Binding UserSettings, IsAsync=True}" AutoGenerateColumns="False">

设置IsAsync = True的关键是允许屏幕绘制

答案 1 :(得分:1)

我的问题已在另一个网站的帖子中得到解答。我没有在我的视图模型中创建ListOfEmployees的新实例,而是清除了现有的实例并添加了我的存储库中的结果:

        private void SearchEmployee()
    {
        if (String.IsNullOrEmpty(this.SearchText) || String.IsNullOrEmpty(this.Location))
        {
            NavigationActions.ShowError("Search Employees.", "Please enter your search text and select a location...");
            return;
        }

        // clear the list and repopulate based on the search criteria
        if (ListOfEmployees != null)
        {
            ListOfEmployees.Clear();

            IList<EmployeeDto> iList = employeeRpository.GetEmployeesByQuery(SearchText, Location, IsActive);
            foreach (EmployeeDto value in iList)
                ListOfEmployees.Add(value);
        }
    }

这就是诀窍。

答案 2 :(得分:1)

你之前的代码也应该有用,但是“魔术字符串”阻碍了它。 属性名称是ListOfEmployees,在其setter中,您使用属性名称ListOfEmployee引发PropertyChanged事件。 's'不见了。

小心你的新代码。它将在ListOfEmployees上为每次插入引发CollectionChanged事件,如果您进行多次插入,这可能会使您的应用程序变慢。 对于许多插入,最好从ObservableCollection派生并实现Reset方法,该方法清除基础Items,添加新项并引发Reset类型的CollectionChanged事件。

答案 3 :(得分:1)

我发现了两种刷新DataGrid的方法:

  1. 一个由VariableLost发布,它与INotifyPropertyChanged一起使用,但有一个缺点。整个DataGrid都具有闪烁效果(一秒钟消失)。看起来不自然。
  2. 其他解决方案是刷新ViewModel或“代码隐藏”中的ObservableCollection(如果您未使用MVVM):

CollectionViewSource.GetDefaultView(collectionName).Refresh();

看起来更自然,因为仅更改受版本影响的单元格。