【问题标题】:WPF MVVM - Update Datagrid of the MainView from a child viewmodelWPF MVVM - 从子视图模型更新 MainView 的 Datagrid
【发布时间】:2019-01-19 05:29:43
【问题描述】:

我认为这可能很简单,但我在谷歌上搜索了一段时间没有成功,我不确定什么是正确的方法。我看到 Prism 可能是一个解决方案,但我正在寻找一些简单的东西。

我有一个 MainViewModel 和一个包含 Datagrid 的 MainView。 MainView 还包含一个 ContentControl,它显示一个 ChildView(DataContext 作为 ChildViewModel)。

我使用 DataTemplate 来关联 View 和 ViewModel。

MainView 的 DataGrid 绑定到 ChildViewModel 的 ObservableCollection。

我希望每次修改此集合时都更新此 DataGrid。 我曾尝试使用 INotifyPropertyChanged。 我尝试使用 OnCollectionChanged。

当我调试时,我可以看到 Collection 已更改并且该事件已触发但如何刷新绑定? (dataGrid 未更新)。

代码如下:

数据模板

<DataTemplate DataType="{x:Type vm:ChildViewModel}">
    <vi:ChildView />
</DataTemplate>

XAML 主视图

     <ContentControl Content="{Binding childViewModel}"/>

     <DataGrid x:Name="DataGridChildren"
                       ItemsSource="{Binding childViewModel.Children,Mode=TwoWay}" 
                       SelectedItem="{Binding childViewModel.SelectedItem}" EnableRowVirtualization="True" IsReadOnly="True" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn">

主视图模型

public ChildViewModel childViewModel { get; set; }

public MainViewModel()
{
    childViewModel = new ChildViewModel();
}

视图模型库

public abstract class ViewModelBase : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, args);
        }
    }

子视图模型

 public class ChildViewModel: ViewModelBase
    {
        private ObservableCollection<Child> _Children;
        public ObservableCollection<Child> Children
        {
            get { return _Children; }
            set
            {
                _Children = value;
                OnPropertyChanged("Children");
                _Children.CollectionChanged +=handler;   
            }
        }

        private void handler(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            //What to do ?
        }

        public ChildViewModel()
        {
            Children = new ObservableCollection<Child>(ChildService.GetAllChild());
        }`    

编辑@lezhkin11

是的,我认为这就是问题所在。但我不知道如何解决它

MainView 后面的代码

void MainView_Loaded(object sender, RoutedEventArgs e)
{  
    mainViewModel = new MainViewModel();
    DataContext = mainViewModel;
}

ChildView 背后的代码

void ChildView_Loaded(object sender, RoutedEventArgs e)
{
     childViewModel = new ChildViewModel();
     DataContext = childViewModel;
}

允许进行新搜索的按钮:

 private void BtnRefresf_Click(object sender, RoutedEventArgs e) // Search
 {
      childViewModel.Search();
 }

然后childViewModel中的一个方法会使用服务给Observable集合一个新的值(我调试的时候可以到达集合的OnpropertyChanged)

   public void Search()
     {
            ObservableCollection<Child> collec = new ObservableCollection<Child>(ChildService.GetAllChild());

            Children = collec;
    }

【问题讨论】:

  • 您使用的逻辑是正确的。我怀疑问题出在 。您只需创建视图和视图模型的另一个实例。因此,您的数据网格绑定到 ChildViewModel 的一个实例,而 ChildView 绑定到另一个实例。这只是一个假设。您能否提供 ChildView 的代码隐藏、其 XAML 以及添加新项目的位置
  • 实际上,我现在正在尝试完全更新该系列。我已经尝试过 Children.Add(..) 我得到了相同的结果。
  • 您有 2 个选项。 1) 删除此方法ChildView_Loaded 并在DataTemplate 中执行&lt;vi:ChildView DataContext="{Binding}" /&gt;。 2) 删除public ChildViewModel childViewModel { get; set; },然后删除ContentControlDataTemplate。你的新 XAML &lt;vi:ChildView x:Name="MyChild" /&gt; &lt;DataGrid ItemsSource="{Binding DataContext.Children, ElementName=MyChild,Mode=TwoWay}"
  • 谢谢。第一个选项不是很方便,因为我在使用 childviewmodel 的视图上有几个控件。我尝试了第二个,但我得到了错误:Cannot find source for binding with reference 'ElementName=MyChild'
  • 它应该可以工作。很简单的场景。看起来您尚未为 ChildView 分配名称。再一次:1)您从 MainViewModel 中删除 ChildViewModel 属性。 2)然后你在XAML中删除ContentControl和DataTemplate 3)直接在XAML中创建ChildView并为其分配名称x:Name="MyChild"

标签: c# wpf mvvm datagrid


【解决方案1】:

您的 DataGrid 绑定到 ChildViewModel 内的 MainViewModel(实例 1)。虽然ChildView 有自己的ChildViewModel(实例2)。

您必须确保两个控件都引用同一个实例。

1) 从 MainViewModel 中完全删除 public ChildViewModel childViewModel { get; set; }

2) 为 ChildView 命名。

<vi:ChildView x:Name="MyChild" />

3) 将 DataGrid 的属性绑定到正确的视图模型

 <DataGrid ItemsSource="{Binding DataContext.Children, ElementName=MyChild, Mode=TwoWay}" />

另外,我建议直接在构造函数中初始化 DataContext。 加载事件为时已晚 - 结果总是有很多 XAML 绑定异常会影响性能(甚至会导致意外行为)

【讨论】:

    猜你喜欢
    • 2014-08-04
    • 2020-01-17
    • 1970-01-01
    • 2016-11-25
    • 2013-02-10
    • 1970-01-01
    • 2014-05-15
    • 2010-10-28
    • 1970-01-01
    相关资源
    最近更新 更多