【问题标题】:WPF -Child datacontext set from the parent ViewModel doesnot contains the modified values in the parent ViewModelWPF - 从父 ViewModel 设置的子数据上下文不包含父 ViewModel 中的修改值
【发布时间】:2018-05-21 10:24:50
【问题描述】:

在我的 WPF 应用程序中,我有一个 MainWindow.xaml,其中嵌入了许多用户控件。我对主窗口和用户控件都有单独的视图模型。在主窗口 ViewModel 中,我创建了一个子 ViewModel 的实例并将其设置为子的数据上下文。

父虚拟机 ChildUserControlVM ChildVM = new ChildUserControlVM (ParentModel.ChildModel);

MainWindow.xaml

但是这种方法不起作用,因为我没有在子视图模型的父视图模型中设置值,反之亦然。

相反,如果我将 Child 模型对象设置为双向工作的父级的数据上下文。

我需要一些解决方案,以便我可以在用户控件中使用 MVVM,同时确保数据从父级传递到子级,反之亦然。 在用户控件中,我将有一些按钮,我想通过 ICommand 在子 Viewmodel 中处理其操作。 添加代码 sn-ps 以供参考 MainWindow.xaml

<Grid Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0">
    <local:ProfileIdentitySettings Visibility="{Binding ProfileIdentitySettingsVisibility,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" DataContext="{Binding ChildProfileIdentityVM}"/>      
</Grid>

MainWindowVM.cs

 ProfileIdentitySettingsVM ChildProfileIdentityVM = new ProfileIdentitySettingsVM(DeviceEditorModel.ProfileIdentitySettings);

ProfileIdentitySettings.xaml

DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.MainWindowVM}">

【问题讨论】:

  • 你能展示你的代码吗?
  • 我已经添加了代码sn-p。这目前不起作用。

标签: wpf mvvm user-controls


【解决方案1】:

我的理解是需要从 MainViewModel 设置 usercontrol Viewmodel。

主视图模型:

 public class MainWindowViewModel : INotifyPropertyChanged, IMainViewModel
{

    public MainWindowViewModel()
    {
        this.Collection = new List<string>();
        this.Child = new ChildUserControlViewModel();
        this.Child.mainViewModel = this;
        this.Child.TextValue = "Justin";
    }
    private List<string> _Collection;

    public List<string> Collection
    {
        get { return _Collection; }
        set { _Collection = value; this.OnPropertyChanged("Collection"); }
    }
    private string _MainValue;
    public string MainValue
    {
        get { return _MainValue; }
        set { _MainValue = value; this.OnPropertyChanged("MainValue"); }
    }
    private ChildUserControlViewModel child;
    public ChildUserControlViewModel Child
    {
        get { return child; }
        set { child = value; this.OnPropertyChanged("Child"); }
    }

}

子用户控件视图模型:

public class ChildUserControlViewModel : INotifyPropertyChanged
{

    public IMainViewModel mainViewModel = null;

    public List<string> Collection
    {
        get { return this.mainViewModel.Collection; }
        set { this.mainViewModel.Collection = value; this.OnPropertyChanged("Collection"); }
    }

    private string _TextValue;
    public string TextValue
    {
        get { return _TextValue; }
        set
        {
            _TextValue = value;
            this.mainViewModel.MainValue = value;
            this.mainViewModel.Collection.Add(value);
            this.OnPropertyChanged("TextValue");
        }
    }
}





 public interface IMainViewModel
    {
        string MainValue { get; set; }

         List<string> Collection { get; set; }
    }

查看:

<Grid>
   <usr:ChildUserControl DataContext="{Binding Child}"/>
</Grid>

【讨论】:

  • 如何从子虚拟机访问父虚拟机中定义的属性?
  • 哦!我的 Unserstading 是您可以为此使用接口
  • 编辑了答案。
  • 这是你期待的还是别的什么??
  • 不完全是。我希望接口对象从父 VM 传递到子 VM。基本上,我需要父 VM 中的一个集合,多个子 VM 可以访问该集合来修改相同的集合属性。父虚拟机可以随时从子虚拟机中提取修改后的值。
【解决方案2】:

父视图模型应该包含子视图模型作为属性,比如

public class ParentViewModel
{
    public ChildViewModel1 ChildViewModel1 { get; set; }
    public ChildViewModel2 ChildViewModel2 { get; set; }
}

您的用户控件不应该有自己的任何视图模型。相反,他们应该公开依赖属性,例如

public partial class MyView1 : UserControl
{
    public string MyProperty { get; set; } // this must be a dependency property
}

在使用 UserControl 时可以绑定,例如在你的 MainWindow 的 XAML 中,比如

<MyView1 MyProperty="{Binding ChildViewModel1.SomeProperty}" />

如果有很多这些可绑定的属性,您可以将 UserControl 的 DataContext 设置为适当的子视图模型:

<MyView1 DataContext="{Binding ChildViewModel1}"
         MyProperty="{Binding SomeProperty}" />

【讨论】:

  • 我已阅读您关于不在 UC 中使用 viewModels 的评论。听起来不错,但是当您设置 DataContext = "{Binding ChildViewModel1}" 时,您将如何重用此类 UC?
  • @Sasha 他在 MainWindow 中这样做,以便 MyView1(UC)可以与其他视图模型重用
  • &lt;MyView1 MyProperty="{Binding ChildViewModel1.SomeProperty}" /&gt; 行位于 MainWindow 的 XAML 中。当然,它假定 MainWindow 的 DataContext 已设置为 ParentViewModel 的实例。因此,您可以轻松地重用 UserControl,例如在同一个 MainWindow 中,但绑定到另一个子视图模型,如 &lt;MyView1 MyProperty="{Binding ChildViewModel2.SomeOtherProperty}" /&gt;
【解决方案3】:

在 xaml 中设置每个用户控件的数据上下文

<UserControl.DataContext>
    <VMPath:ChildVM/>
</UserControl.DataContext>

然后为 MainWindow 中定义的用户控件添加加载事件

<ViewPath:MyUserControl x:Name="uc1" Loaded="UserControlLoaded"/>

在您的代码中,您将拥有

    private void UserControlLoaded(object sender, RoutedEventArgs e)
    {
        ParentVM vm = this.DataContext as VM;
        ChildVM cvm = uc1.DataContext as ChildVM;
        // do your stuff
    }

如果您需要执行的操作始终相同,您可以对所有 UserControl 使用 1 种方法。

基本上你要做的就是下面的操作。

  • 将用户控件的 dantacontext 静态设置为“空”ChildVM 的实例

  • 加载您的控件

  • 加载完成后,在 ChildVM 上执行您需要执行的操作(例如设置一些属性)

在您真正使用您的应用程序之前完成所有这些操作

【讨论】:

  • 不要这样做。绝不!设置 UserControl 的 DataContext 是一种反模式。它有效地防止了控件的属性可以绑定到继承的 DataContext,这是您通常想要发生的。虽然网上很多“WPF专家”都这么告诉你,但是设置一个UserControl的DataContext难免会给你带来麻烦。
  • @Clemens OP 没有给我们很多细节,但据我了解 ChildVM 是一个不同的视图模型。所以实际上OP的用户控件只需要主windows datacontext设置一些Properties,不需要继承它的datancontext。我只是提出了一个简单的方法来做到这一点。
  • 设置 UserControl 的 DataContext 总是错误的。参见例如stackoverflow.com/a/28815689stackoverflow.com/a/44729258。你在这里给出了一个非常糟糕的建议。
  • @Clemens 如果 OP 需要将其用户控件与不同的视图模型一起使用,那将是一个非常糟糕的建议。在这里,我认为我看到的 99% 的问题(尤其是来自最新用户的问题)都使用几个强耦合的视图/视图模型来投影他们的应用程序,我认为这种情况也不例外。如果不是这种情况,那么您的回答也很糟糕(除非 ChildVM 确实从 ParentVM 继承)。如果它们是单独的 Viewmodel,我认为你应该这样做 this 完全对 MVVM 友好
  • 我不是在谈论应用程序及其主窗口。你当然会在那里设置一个视图模型。但是,这里有很多人(包括我)经常回答诸如“为什么我的 UserControl 绑定不起作用”之类的问题。通常是因为提问者犯了上述错误。不管你谈多久,它仍然是错误的。我们已经在这里讨论过很多次了......
猜你喜欢
  • 1970-01-01
  • 2017-11-21
  • 2011-06-20
  • 1970-01-01
  • 2018-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多