【问题标题】:WPF MVVM PaginationWPF MVVM 分页
【发布时间】:2017-05-12 10:58:04
【问题描述】:

我有一个分页视图的用户控件,它有自己的视图模型。我在带有数据网格的页面中添加了分页,该数据网格也具有单独的视图模型。

我的问题是,每次在分页视图模型中执行命令时,如何更新页面视图模型中的 ObservableCollection?

这是我的 PagingControl.xaml

<StackPanel Width="Auto"
        Orientation="Horizontal">
        <Button                
            Margin="4,0"
            Content="&lt;&lt;"
            Command="{Binding FirstCommand}"/>
        <Button
            Margin="4,0"
            Content="&lt;"
            Command="{Binding PreviousCommand}"/>
        <StackPanel
            VerticalAlignment="Center"
            Orientation="Horizontal">
            <TextBlock
                Text="{Binding Start}"/>
            <TextBlock
                Text=" to "/>
            <TextBlock
                Text="{Binding End}"/>
            <TextBlock
                Text=" of "/>
            <TextBlock
                Text="{Binding TotalItems}"/>
        </StackPanel>
        <Button
            Margin="4,0"
            Content="&gt;"
            Command="{Binding NextCommand}"/>
        <Button
            Margin="4,0"
            Content="&gt;&gt;"
            Command="{Binding LastCommand}"/>
        <ComboBox Width="100" ItemsSource="{Binding ItemsPerPage}" SelectedValue="{Binding ItemCount}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                <i:InvokeCommandAction Command="{Binding CountChangedCommand}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ComboBox>
    </StackPanel>

PagingViewModel.cs

public class PagingViewModel : ViewModelBase
{
    private ObservableCollection<DataModel> _data;

    private int start = 0;
    private int itemCount = 10;
    private int totalItems = 0;
    private readonly List<int> count;

    private ICommand _firstCommand;
    private ICommand _previousCommand;
    private ICommand _nextCommand;
    private ICommand _lastCommand;
    private ICommand _countchangedCommand;

    public ObservableCollection<DataModel> Data
    {
        get { return _data; }
        set
        {
            if (_data!= value)
            {
                _data= value;
                OnPropertyChanged("Data");
            }
        }
    }

    public PagingViewModel()
    {
        count = new List<int> { 10, 20, 30};
        RefreshData();
    }

    public int Start { get { return start + 1; } }

    public int End { get { return start + itemCount < totalItems ? start + itemCount : totalItems; } }

    public int TotalItems { get { return totalItems; } }

    public List<int> Count { get { return count; } }

    public int ItemCount { get { return itemCount; } set { itemCount = value; OnPropertyChanged("ItemCount"); } }

    public ICommand FirstCommand
    {
        get
        {
            if (_firstCommand == null)
            {
                _firstCommand = new RelayCommand
                (
                    param =>
                    {
                        start = 0;
                        RefreshData();
                    },
                    param =>
                    {
                        return start - itemCount >= 0 ? true : false;
                    }
                );
            }

            return _firstCommand;
        }
    }

    public ICommand PreviousCommand
    {
        get
        {
            if (_previousCommand == null)
            {
                _previousCommand = new RelayCommand
                (
                    param =>
                    {
                        start -= itemCount;
                        RefreshData();
                    },
                    param =>
                    {
                        return start - itemCount >= 0 ? true : false;
                    }
                );
            }

            return _previousCommand;
        }
    }

    public ICommand NextCommand
    {
        get
        {
            if (_nextCommand == null)
            {
                _nextCommand = new RelayCommand
                (
                    param =>
                    {
                        start += itemCount;
                        RefreshData();
                    },
                    param =>
                    {
                        return start + itemCount < totalItems ? true : false;
                    }
                );
            }

            return _nextCommand;
        }
    }

    public ICommand LastCommand
    {
        get
        {
            if (_lastCommand == null)
            {
                _lastCommand = new RelayCommand
                (
                    param =>
                    {
                        start = (totalItems / itemCount - 1) * itemCount;
                        start += totalItems % itemCount == 0 ? 0 : itemCount;
                        RefreshData();
                    },
                    param =>
                    {
                        return start + itemCount < totalItems ? true : false;
                    }
                );
            }

            return _lastCommand;
        }
    }

    public ICommand CountChangedCommand
    {
        get
        {
            if (_countchangedCommand == null)
            {
                _countchangedCommand = new RelayCommand
                (
                    param =>
                    {
                        start = 0;
                        RefreshData();
                    },
                    param =>
                    {
                        return ((totalItems - itemCount) > -10) ? true : false;
                    }
                );
            }

            return _countchangedCommand;
        }
    }

    public void RefreshData()
    {
        _data= GetData(start, itemCount, out totalItems);
DataViewModel vm = new DataViewModel(this);

        OnPropertyChanged("Start");
        OnPropertyChanged("End");
        OnPropertyChanged("TotalItems");
    }
}

这是我的页面的视图模型:DataViewModel.cs

public class DataViewModel: ViewModelBase
{
    private ObservableCollection<DataModel> _data;

    public ObservableCollection<DataModel> Data
    {
        get { return _data; }
        set
        {
            if (_data!= value)
            {
                _data= value;
                OnPropertyChanged("Data");
            }
        }
    }

    public DataViewModel(PagingViewModel pagevm)
    {
        _data = new ObservableCollection<DataModel>();
        _data= pagevm.Data; 
    }

}

我的 Data 属性绑定到 DataView.xaml 中 DataGrid 的 ItemSource,DataContext 设置为 DataViewModel。

【问题讨论】:

    标签: c# wpf mvvm pagination


    【解决方案1】:

    这是一个非常详细的问题!

    对于您的刷新问题,我看到了一些选项: 在 RefreshData 中设置您的 Data 时,您应该使用属性的公共设置器而不是 _data。如果不这样做,您将永远不会使用 OnPropertyChanged 通知视图您的整个集合已更改。

    所以你需要更换:

    _data= GetData(start, itemCount, out totalItems);
    

    与:

    Data= GetData(start, itemCount, out totalItems);
    

    顺便说一句,您的 DataViewModel 对我来说毫无意义。您的 _audits 字段无处可见,并且从未在此 ViewModel 中设置 ObservableCollection Data。我相信你的问题一定来自这个。

    PS:

    另一方面,我有一些与您的问题没有直接关系的建议:

    首先,当您想在设置之前检查某个 RelayCommand 是否为 null 时,您可能需要使用 ??运营商:https://msdn.microsoft.com/en-us/en-en/library/ms173224.aspx.

    其次,我高度建议您将 RelayCommands 行为放入方法中。当你最终得到十几个命令时,维护 RelayCommand 真是一团糟,所有事情都发生在 lambdas 中。

    这样你将替换这个:

    public ICommand NextCommand
    {
        get
        {
            if (_nextCommand == null)
            {
                _nextCommand = new RelayCommand
                (
                    param =>
                    {
                        start += itemCount;
                        RefreshData();
                    },
                    param =>
                    {
                        return start + itemCount < totalItems ? true : false;
                    }
                );
            }
               return _nextCommand;
        }
    }
    

    有了这个:

     public ICommand NextCommand
     {
         get
         {
             return _nextCommand = _nextCommand ?? new RelayCommand(Next, CanExecuteNext);
         }
     }
    
     private void Next()
     {
         start += itemCount;
         RefreshData();
     }
    
     private bool CanExecuteNext()
     {
         return start + itemCount < totalItems ? true : false;
     }
    

    【讨论】:

    • 嗨 yan yankelevich,我的 AuditTrail 部分不好。它应该是 DataViewModel 的构造函数,我已经对其进行了编辑,并将尝试您的答案。谢谢! :)
    • 我实现了你的答案,但我现在的问题似乎无法更新我的 DataGrid ,其中 Data 是有界的。这些值已经通过,但数据网格没有根据 Observable Collection 的新值更新:(
    【解决方案2】:

    听起来您的命令需要能够访问您的页面视图模型。为了让他们这样做,您的分页 viewModel 需要保存对页面 viewModel 的引用(以便您的分页 viewModel 可以将其传递给相关命令)。

    我建议使用属性注入。在您的 PagingViewModel 中添加这样的属性;

        public AuditTrailViewModel AuditTrailViewModel { get; set; }
    

    (如果需要,请提供属性更改通知)。

    在您的命令中,您现在可以访问 AuditTrailViewModel 的属性

    public ICommand LastCommand
    {
        get
        {
            if (_lastCommand == null)
            {
                _lastCommand = new RelayCommand
                (
                    param =>
                    {
                        start = (totalItems / itemCount - 1) * itemCount;
                        start += totalItems % itemCount == 0 ? 0 : itemCount;
                        AuditTrailViewModel.Data = //Now you can update your viewModel
                        RefreshData();
                    },
                    param =>
                    {
                        return start + itemCount < totalItems ? true : false;
                    }
                );
            }
    
            return _lastCommand;
        }
    }
    

    【讨论】:

    • 嗨,mark_h,我的 AuditTrail 部分不好。它应该是 DataViewModel 的构造函数,我已经对其进行了编辑,并将尝试您的答案。谢谢! :)
    • 试过你的分析器并在这一行给我一个“对象未设置为实例”错误>>AuditTrailViewModel.Data = //Now you can update your viewModel
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-25
    • 2012-09-02
    • 2011-07-15
    • 2016-07-17
    • 2018-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多