简体   繁体   English

如何从Page访问MainWindow视图模型?

[英]How to get access to the MainWindow viewmodel from Page?

I'm trying to understand binding system in WPF. 我试图了解WPF中的绑定系统。 In my example i need to get access to MainWindow viewmodel from Page in XAML. 在我的示例中,我需要从XAML中的Page访问MainWindow视图模型。

I have one solution to implement this. 我有一个解决方案来实现这一目标。 But i want to know more different ways 但我想知道更多不同的方式

MainWindow.xaml MainWindow.xaml

<Window x:Class="FunAnkiWPF.MainWindow"
    ...omitted for brevity
    Height="450" Width="800"
    DataContext="{Binding ViewModel, RelativeSource={RelativeSource 
Self}}">

MainWindow.xaml.cs MainWindow.xaml.cs

public partial class MainWindow : Window
{        
    public MainWindowViewModel ViewModel { get; set; }

    public MainWindow()
    {
        ViewModel = new MainWindowViewModel(this);
        InitializeComponent();            
    }    
}

StartPage.xaml ( usual page ) StartPage.xaml常规页面

StartPage.xaml.cs ( One solution that works ) StartPage.xaml.cs一种有效的解决方案

public partial class StartPage : Page
{
    public StartPage()
    {
        InitializeComponent();
        DataContext = App.Current.MainWindow.DataContext;
    }
}

How to get a direct access to the MainWindow ViewModel property (in XAML and in codebehind)? 如何直接访问MainWindow ViewModel属性(在XAML和代码隐藏中)? How to get access to another datacontext in XAML (like in my StartPage codebehind)? 如何访问XAML中的另一个数据上下文(例如在我的StartPage代码后面)?

The short answer to binding from a child control to a property in the parent window's datacontext is relativesource eg: 从子控件绑定到父窗口的数据上下文中的属性的简短答案是relativesource,例如:

         <TextBlock Text="{Binding Path=DataContext.MainWinVMString, 
          RelativeSource={RelativeSource  AncestorType={x:Type Window}}}"

Here's an example to give you the flavour of what I am suggesting. 这是一个示例,可以为您提供我所建议的风味。

The MainWindow markup is a bit quick n dirty. MainWindow标记有点麻烦。 I would put datatemplates in a resource dictionary merged by app.xaml. 我会将datatemplates放在由app.xaml合并的资源字典中。

    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <DataTemplate DataType="{x:Type local:LoginViewModel}">
        <local:LoginUC/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:UserViewModel}">
        <local:UserUC/>
    </DataTemplate>
</Window.Resources>
<Window.DataContext>
    <local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="100"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <ItemsControl ItemsSource="{Binding NavigationViewModelTypes}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button Content="{Binding Name}"
                    Command="{Binding DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                    CommandParameter="{Binding VMType}"
                />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    <ContentControl Grid.Column="1"
                    Content="{Binding CurrentViewModel}"
                    />
</Grid>

Viewmodel for that: 的视图模型:

public class MainWindowViewModel : INotifyPropertyChanged
{
    public string MainWinVMString { get; set; } = "Hello from MainWindoViewModel";

    public ObservableCollection<TypeAndDisplay> NavigationViewModelTypes { get; set; } = new ObservableCollection<TypeAndDisplay>
        (
        new List<TypeAndDisplay>
        {
           new TypeAndDisplay{ Name="Log In", VMType= typeof(LoginViewModel) },
           new TypeAndDisplay{ Name="User", VMType= typeof(UserViewModel) }
        }
        );

    private object currentViewModel;

    public object CurrentViewModel
    {
        get { return currentViewModel; }
        set { currentViewModel = value; RaisePropertyChanged(); }
    }
    private RelayCommand<Type> navigateCommand;
    public RelayCommand<Type> NavigateCommand
    {
        get
        {
            return navigateCommand
              ?? (navigateCommand = new RelayCommand<Type>(
                vmType =>
                {
                    CurrentViewModel = null;
                    CurrentViewModel = Activator.CreateInstance(vmType);
                }));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Relaycommand is from nuget package mvvmlightlibs. Relaycommand来自nuget包mvvmlightlibs。

UserUC: UserUC:

<Grid Background="pink">
    <TextBlock Text="This is the User module Control"
               VerticalAlignment="Top"
               />
    <TextBlock Text="{Binding Path=DataContext.MainWinVMString, RelativeSource={RelativeSource  AncestorType={x:Type Window}}}"
               VerticalAlignment="Bottom"
               />
</Grid>

Full working sample: https://1drv.ms/u/s!AmPvL3r385QhgqIZUul-ppiIHZ9uyA 完整的工作示例: https : //1drv.ms/u/s!AmPvL3r385QhgqIZUul-ppiIHZ9uyA

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM