【问题标题】:WPF MVVM ListBox does not display last recordWPF MVVM ListBox 不显示最后一条记录
【发布时间】:2016-04-12 15:24:44
【问题描述】:

我觉得我遇到的问题很奇怪。

我有一个使用 MVVM 模式的 WPF 应用程序。

我使用 Linq-to-SQL 从我的数据库中检索数据,并使用绑定在 ListBox 中显示描述字段数据。

它有效,但不完全。由于某种原因,最后一条记录不显示。我已经验证它是从数据库中获取的。无法选择;它根本不存在。

让记录出现的唯一方法是将焦点设置到 ListBox 并滚动鼠标滚轮或使用键盘实际向下移动以越过最后一条记录(应该是倒数第二条记录)。一旦你这样做了,记录就会出现。

另一种显示记录的方法是更新列表框中的任何记录。我有一个 TextBox 以双向模式绑定到 ListBox 的 SelectedItem,所以当我选择一个项目时,更改 TextBox 中的文本并单击更新按钮,它会调用命令来进行数据库更新,效果很好,但是最后一条记录的缺失记录也会出现。

ListBox 和 ListView 是否存在渲染问题,因为我都试过了?为什么 ListBox 似乎需要在最后一个项目出现之前“重绘”?

CategoryModel.cs

public class CategoryModel
{
    public int CategoryID { get; set; }
    public string Description { get; set; }

    public List<CategoryModel> categories = new List<CategoryModel>();
    readonly SalesLinkerDataContext _dbContext = new SalesLinkerDataContext();

    public void GetCategories()
    {
        categories.Clear();

        var result = _dbContext.tblSalesCategories.ToList();

        foreach (var item in result)
        {
            categories.Add(new CategoryModel
            {
                CategoryID = item.CategoryID,
                Description = item.Description.Trim()
            });
        }
    }

    internal void Update(CategoryModel cm)
    {
        try
        {
            var category = (from a in _dbContext.tblSalesCategories
                where a.CategoryID == cm.CategoryID
                select a).FirstOrDefault();

            if (category != null)
            {
                category.Description = cm.Description;
                _dbContext.SubmitChanges();
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
}

CategoriesViewModel.cs

public class CategoriesViewModel : ViewModelBase, IPageViewModel
{
    public CategoryModel Categories = new CategoryModel();

    private DelegateCommand _getCategoriesCommand;
    private DelegateCommand _updateCategoryCommand;


    /// <summary>
    /// Describes the name that will be used for the menu option
    /// </summary>
    public string Name
    {
        get { return "Manage Categories"; }  

    }

    public string Description
    {
        get { return Categories.Description; }
        set
        {
            Categories.Description = value;
            OnPropertyChanged("Description");
        }
    }

    public List<CategoryModel> ReceivedCategories
    {
        get { return Categories.categories; }

        set
        {
            Categories.categories = value;
            OnPropertyChanged("ReceivedCategories");
        }
    }

    public ICommand GetCategoriesCommand
    {
        get
        {
            if (_getCategoriesCommand == null)
            {
                _getCategoriesCommand = new DelegateCommand(GetCategories, CanGetCategories);
            }

            return _getCategoriesCommand;
        }   
    }

    private bool CanGetCategories()
    {
        return true;
    }

    private void GetCategories()
    {
        Categories.GetCategories();
        ReceivedCategories = Categories.categories;

    }

    public ICommand UpdateCategoryCommand
    {
        get
        {
            if (_updateCategoryCommand == null)
            {
                _updateCategoryCommand = new DelegateCommand(UpdateCategory, CanUpdateCategory);
            }

            return _updateCategoryCommand;
        }


    }

    private bool CanUpdateCategory()
    {
        return true;
    }

    private void UpdateCategory()
    {

        Categories.Update(Categories);
    }

}

CategoriesView.xaml

<UserControl x:Class="SalesLinker.CategoriesView"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
  mc:Ignorable="d" 
  d:DesignHeight="300" d:DesignWidth="600" Background="White" >

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <i:InvokeCommandAction Command="{Binding GetCategoriesCommand}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

<Grid >
    <Grid.RowDefinitions>
        <RowDefinition Height="45"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="250"/>
        <ColumnDefinition Width="100"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Label Grid.Row="0" Grid.Column="0" Margin="20,0,0,0" FontSize="20" HorizontalAlignment="Center" Content="Categories"/>
    <ListView x:Name="LstCategories" ItemsSource="{Binding ReceivedCategories, Mode=TwoWay}" Grid.Column="0" Grid.Row="1" 
              VerticalAlignment="Stretch"
              Background="LightGray"
              ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
              SelectionChanged="LstCategories_OnSelectionChanged">

        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" >
                    <TextBlock Text="{Binding Description }"/>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

    <Button Command="{Binding AddCategoryCommand}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Height="50" Width="50" Margin="0,20,0,0" Background="Transparent" BorderThickness="0" BorderBrush="Transparent" >
        <Image Source="/Images/Plus.png"/>
    </Button>
    <Button Command="{Binding RemoveCategoryCommand}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Height="50" Width="50" Margin="0,75,0,0" Background="Transparent" BorderThickness="0">
        <Image Source="/Images/Minus.png"/>
    </Button>

    <Grid Grid.Row="1" Grid.Column="2">
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="75"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Label VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="0" Content="Description:"/>

        <TextBox DataContext="CategoryModel" Grid.Row="0" Grid.Column="1" Width="250" Height="Auto" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" 
                 Text="{Binding SelectedItem.Description, ElementName=LstCategories}"/>


        <Button Command="{Binding UpdateCategoryCommand}" 
                Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Margin="10,0,0,0" Height="20" Width="120" Content="Update Description"/>

    </Grid>
</Grid>

我对 MVVM 很陌生,所以希望我只是没有看到简单的东西。

【问题讨论】:

  • 代码看起来不错。尝试临时排除使用 _dbContext:生成具有已知元素计数的假列表并查看结果。
  • 结果相同,最后一项不显示。

标签: wpf xaml mvvm listbox


【解决方案1】:

由于某种原因,最后一条记录没有显示。我已经验证它是从数据库中获取的。

如果您从数据库中获取所有数据,那么可以得出结论,为什么您看不到最后一个项目是因为您使用了不正确的布局。我的意思是静态布局。

我建议你使用动态布局,而不是静态的。我的意思是它很糟糕:

<Grid.RowDefinitions>
    <RowDefinition Height="45"/>
    <RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
    <ColumnDefinition Width="250"/>
    <ColumnDefinition Width="100"/>
    <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

下面的代码更好,它使您可以看到所有要查看的项目,并根据您的WidthHeight 的显示和WindowUserControl 调整大小:

   <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*"/>
        <ColumnDefinition Width="2*"/>
        <ColumnDefinition Width="2*"/>
    </Grid.ColumnDefinitions>

让我展示完整的例子:

<Grid>
  <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*"/>
        <ColumnDefinition Width="2*"/>
        <ColumnDefinition Width="2*"/>
    </Grid.ColumnDefinitions>
    <Label Grid.Row="0" Grid.Column="0" Margin="20,0,0,0" FontSize="20" HorizontalAlignment="Center" Content="Categories"/>
    <ListView x:Name="LstCategories" ItemsSource="{Binding ReceivedCategories, Mode=TwoWay}" Grid.Column="0" Grid.Row="1" 
          VerticalAlignment="Stretch"
          Background="LightGray"
          ScrollViewer.HorizontalScrollBarVisibility="Disabled">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" >
                    <TextBlock Text="{Binding Description }"/>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>

    </ListView>

    <Button Command="{Binding AddCategoryCommand}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Height="50" Width="50" Margin="0,20,0,0" Background="Transparent" BorderThickness="0" BorderBrush="Transparent" >
        <Image Source="/Images/Plus.png"/>
    </Button>
    <Button Command="{Binding RemoveCategoryCommand}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Height="50" Width="50" Margin="0,75,0,0" Background="Transparent" BorderThickness="0">
        <Image Source="/Images/Minus.png"/>
    </Button>

    <Grid Grid.Row="1" Grid.Column="2">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1.5*"/>
            <ColumnDefinition Width="2*"/>
        </Grid.ColumnDefinitions>

        <Label VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Row="0" Grid.Column="0" Content="Description:"/>

        <TextBox DataContext="CategoryModel" Grid.Row="0" Grid.Column="1" Height="Auto" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0,0,0" 
             Text="{Binding SelectedItem.Description, ElementName=LstCategories}"/>


        <Button Command="{Binding UpdateCategoryCommand}" 
            Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Content="Update Description"/>
</Grid>

更新:

为了打消疑虑,我做了一个测试,显示所有项目都显示出来了:

我做了一些测试模型类:

public class FooClass
{
    public string Description { get; set; }
}

我已经循环填充了你的ListView

public MainWindow()
{
   InitializeComponent();
   PopulateCollection();
}

private void PopulateCollection()
{
   List<FooClass> fooColl = new List<FooClass>();
   for (int i = 0; i <= 1000; i++)
   {
      fooColl.Add(new FooClass() { Description=i.ToString()});
   }
   LstCategories.ItemsSource = fooColl;       
}

XAML:

<ListView x:Name="LstCategories" Grid.Column="0" Grid.Row="1"
    VerticalAlignment="Stretch"
      Background="LightGray"
      ScrollViewer.HorizontalScrollBarVisibility="Disabled">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" >
                    <TextBlock Text="{Binding Description }"/>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>

 </ListView>

结果是:

【讨论】:

  • 没有区别。我不认为这是布局问题。如果我把 Grid 里面除了 Grid Control 和 ListView Control 之外的所有东西都取出来,就会出现完全相同的问题。
  • @Neill 你确定你已经从数据库中获得了所有项目,包括最后一个项目吗?您是否在调试器中看到数据库查询中有最后一项?
  • 是的,100% 确定。
  • 是的,可以,所以控制没有损坏。我还测试了使用假集合 FooClass 和 Binding 在 Code Behind 中的 ListView 的 ItemsSource,这似乎有效。那么问题出在 ViewModel 上吗?
  • 标记为答案。没有解决我的问题,但至少说明了问题不是什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-02
  • 2015-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多