C# 将数据绑定到WPF(MVVM)中的子视图

C# 将数据绑定到WPF(MVVM)中的子视图,c#,.net,wpf,mvvm,data-binding,C#,.net,Wpf,Mvvm,Data Binding,我正在尝试使用WPF和MVVM协议构建一个应用程序。应用程序有一个窗口和多个视图(UserControls)。其中一个视图中还包含子视图,用于显示不同的数据 我的问题 我无法理解如何将数据绑定到子视图。我试图理解数据是如何绑定的,但我只能将数据绑定到一个级别 代码 下面是一些代码。我希望这能使我更容易理解我的问题 App.xaml.cs public partial class App : Application { private Engine _engine; prote

我正在尝试使用WPF和MVVM协议构建一个应用程序。应用程序有一个窗口和多个视图(UserControls)。其中一个视图中还包含子视图,用于显示不同的数据

我的问题 我无法理解如何将数据绑定到子视图。我试图理解数据是如何绑定的,但我只能将数据绑定到一个级别

代码

下面是一些代码。我希望这能使我更容易理解我的问题

App.xaml.cs

public partial class App : Application
{

    private Engine _engine;

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        MainWindow window = new MainWindow();
        _engine = new Engine("test");

        var viewModel = new MainWindowViewModel(_engine);

        EventHandler handler = null;
        handler = delegate
        {
            viewModel.RequestClose -= handler;
            window.Close();
        };
        viewModel.RequestClose += handler;
        window.DataContext = viewModel;

        window.Show();
    }
}
    public WorkspaceViewModel()
    {
        _currentView = new InjectorView();

    }        
    public UserControl CurrentView
    {
        get { return _currentView; }
    }
    public WorkspaceView()
    {
        InitializeComponent();
        this.DataContext = new WorkspaceViewModel();
    }
这里是我创建引擎对象并将其传递给MainWindowViewModel的地方,我想进一步绑定视图层次结构

main window.xaml

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:"
    xmlns:ViewModels="clr-namespace:ViewModels" 
    xmlns:View="clr-namespace:Views"
    x:Class="MainWindow" 
    Title="title" Height="800" Width="1200"
    WindowStartupLocation="CenterScreen"   Icon="Resources/Images/logo.png"
>

<DockPanel Margin="0" Background="#FF4F4F4F" LastChildFill="True">
    <Menu DockPanel.Dock="Top" Height="20">
        <MenuItem Header="File">
            <MenuItem Header="Exit"/>
        </MenuItem>
    </Menu>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" MinWidth="200" MaxWidth="200"/>
            <ColumnDefinition Width="5*"/>
        </Grid.ColumnDefinitions>

        <View:TabView Grid.Column="0"/>

        <View:WorkspaceView Grid.Column="1"/>
    </Grid>
</DockPanel>
<UserControl x:Class="Views.WorkspaceView"
         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:local="clr-namespace:Views"
         xmlns:ViewModels="clr-namespace:ViewModels" 
         mc:Ignorable="d" 
         d:DesignHeight="750"
         d:DesignWidth="1000"             
         d:DataContext="{d:DesignInstance ViewModels:WorkspaceViewModel}"
         >

<Grid>
    <Label x:Name="label" Height="750" VerticalAlignment="Top" FontSize="60" Foreground="White" Content="{Binding Engine.BarCode}"/>
    <Grid Margin="40">
        <Grid.Background>
            <ImageBrush ImageSource="/;component/Resources/Images/logo.png" Stretch="Uniform"/>
        </Grid.Background>
        <ContentPresenter Content="{Binding CurrentView}"/>
    </Grid>

    <DockPanel>

        <!--ContentPresenter Content="{Binding CurrentView}"/-->
    </DockPanel>
</Grid>
<UserControl x:Class="Views.InjectorView"
         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:local="clr-namespace:Views"
         xmlns:ViewModels="clr-namespace:ViewModels" 
         mc:Ignorable="d" 
         d:DesignHeight="750"
         d:DesignWidth="1000"
         d:DataContext="{d:DesignInstance ViewModels:InjectorViewModel}"
         >
<Grid Background="#FFAEAEAE">
    <Label x:Name="label1" Content="{Binding Engine.BarCode}"/>
</Grid>
</UserControl>
  • 更新:
    \u currentView=new InjectorView()仅用于测试,当前视图应根据在另一个视图中按下的按钮进行更改*
WorkspaceView.xaml.cs

public partial class App : Application
{

    private Engine _engine;

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        MainWindow window = new MainWindow();
        _engine = new Engine("test");

        var viewModel = new MainWindowViewModel(_engine);

        EventHandler handler = null;
        handler = delegate
        {
            viewModel.RequestClose -= handler;
            window.Close();
        };
        viewModel.RequestClose += handler;
        window.DataContext = viewModel;

        window.Show();
    }
}
    public WorkspaceViewModel()
    {
        _currentView = new InjectorView();

    }        
    public UserControl CurrentView
    {
        get { return _currentView; }
    }
    public WorkspaceView()
    {
        InitializeComponent();
        this.DataContext = new WorkspaceViewModel();
    }
InjectorView.xaml

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:"
    xmlns:ViewModels="clr-namespace:ViewModels" 
    xmlns:View="clr-namespace:Views"
    x:Class="MainWindow" 
    Title="title" Height="800" Width="1200"
    WindowStartupLocation="CenterScreen"   Icon="Resources/Images/logo.png"
>

<DockPanel Margin="0" Background="#FF4F4F4F" LastChildFill="True">
    <Menu DockPanel.Dock="Top" Height="20">
        <MenuItem Header="File">
            <MenuItem Header="Exit"/>
        </MenuItem>
    </Menu>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" MinWidth="200" MaxWidth="200"/>
            <ColumnDefinition Width="5*"/>
        </Grid.ColumnDefinitions>

        <View:TabView Grid.Column="0"/>

        <View:WorkspaceView Grid.Column="1"/>
    </Grid>
</DockPanel>
<UserControl x:Class="Views.WorkspaceView"
         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:local="clr-namespace:Views"
         xmlns:ViewModels="clr-namespace:ViewModels" 
         mc:Ignorable="d" 
         d:DesignHeight="750"
         d:DesignWidth="1000"             
         d:DataContext="{d:DesignInstance ViewModels:WorkspaceViewModel}"
         >

<Grid>
    <Label x:Name="label" Height="750" VerticalAlignment="Top" FontSize="60" Foreground="White" Content="{Binding Engine.BarCode}"/>
    <Grid Margin="40">
        <Grid.Background>
            <ImageBrush ImageSource="/;component/Resources/Images/logo.png" Stretch="Uniform"/>
        </Grid.Background>
        <ContentPresenter Content="{Binding CurrentView}"/>
    </Grid>

    <DockPanel>

        <!--ContentPresenter Content="{Binding CurrentView}"/-->
    </DockPanel>
</Grid>
<UserControl x:Class="Views.InjectorView"
         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:local="clr-namespace:Views"
         xmlns:ViewModels="clr-namespace:ViewModels" 
         mc:Ignorable="d" 
         d:DesignHeight="750"
         d:DesignWidth="1000"
         d:DataContext="{d:DesignInstance ViewModels:InjectorViewModel}"
         >
<Grid Background="#FFAEAEAE">
    <Label x:Name="label1" Content="{Binding Engine.BarCode}"/>
</Grid>
</UserControl>

但是如果我从WorkspaceView.xaml中删除
d:DataContext=“{d:DesignInstance ViewModels:WorkspaceViewModel}”
,并添加
this.DataContext=new WorkspaceViewModel()
到c#文件中,对于xaml代码,它将显示当前视图(InjectorView)。现在唯一的问题是,当我尝试在InjectorView
{Binding Engine.BarCode}
中绑定一些数据时,它不会显示与以前相同的字符串(我想它不再是对象的同一个实例了??)

我错过了什么?我是否完全错误地解释了MVVM和wpf


(由于产品的原因,我不得不删除一些代码(例如名称空间)

您肯定误解了很多

首先,
\u currentView=newinjectorview()不应出现在ViewModel中。ViewModels不应该包含任何可视类(您自己的视图类和UI类)的任何引用。您应该为该视图实例化ViewModel

接下来,如果该
CurrentView
始终是
InjectorView
的一个实例(这意味着它不可能是其他的),那么您可以简单地执行以下操作:

<View:InjectorView>
    <View:InjectorView.DataContext>
        <ViewModel:InjectorViewModel />
    <View:InjectorView.DataContext>
</View:InjectorView>
工作空间视图:

<ContentControl Content="{Binding MyCurrentView}">
    <ContentControl.Resources>
        <DataTemplate DataType="{x:Type ViewModels:InjectorViewModel}">
            <local:InjectorView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type ViewModels:MySecondViewModel}">
            <local:MySecondView />
        </DataTemplate>
        .....
        ....
    </ContentControl.Resources>
</ContentControl>
您无法从视图实例化ViewModel,因为对于单例实现,必须将构造函数设置为私有的。您将改为提供对静态实例的绑定


总的来说,我只需要使用一个单例类来充当存储库。这对我来说似乎很容易实现。

谢谢。这澄清了“d:DataContext=“{d:DesignInstance ViewModels:InjectorViewModel}”为什么我删除这一行时它没有更改任何内容:)关于将视图与viewmodel分离(对于currentView)我可以理解。我忘了说视图将更改为另一个视图,而不总是InjectorView。我该如何处理这个问题?非常感谢@Jai为您提供的时间。我将尝试实施这个策略,并看看它是如何进行的。谢谢,实施您的建议效果很好。我正在努力解决如何从顶部视图绑定数据的问题(主窗口)转到InjectorView。你有什么指导方针如何处理这个问题吗?@robin再次更新。