UserControl在拥有窗口wpf中导航

时间:2016-06-19 17:17:18

标签: wpf xaml

在XAML / WPF中我有一个包含Frame的主窗口,我打算为给定的应用程序视图放置一个用户控件。

<Window x:Class="MyApp.MainWindow"
    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:ignore="http://www.galasoft.ch/ignore"
    mc:Ignorable="d ignore"
    DataContext="{Binding Main, Source={StaticResource Locator}}">
    <Grid x:Name="LayoutRoot">
        <Frame Source="Main/MainUserControl.xaml" Name="Main" />
    </Grid>
</Window>

现在我想将此Frame导航到MainUserControl中的其他源:

<UserControl x:Class="MyApp.View.MainMenu.MainMenuUserControl"
         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:lex="http://wpflocalizeextension.codeplex.com"
         xmlns:command="clr-namespace:MyApp.Command"
         mc:Ignorable="d" 
         Style="{StaticResource Localizable}"
         DataContext="{Binding MainMenu, Source={StaticResource Locator}}">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Button Content="{lex:Loc About}" FontSize="28" Grid.Row="1" Command="NavigationCommands.GoToPage" CommandParameter="/Menu/AboutUserControl.xaml" />
    </Grid>
</UserControl>

但导航按钮About在执行期间保持不活动状态。我正确验证了/Menu/AboutUserControl.xaml存在。

我显然做错了什么。如何从用户控件中导航拥有窗口的框架?优选通过XAML?

1 个答案:

答案 0 :(得分:1)

我假设您正在使用MVVM框架。 (我已经在这里添加了关键元素,以防你不这样做。)

您的MainWindow.xaml应使用“ItemsControl”而不是“Frame”。框架可以工作,但更好的方法是使用ItemsControl,如下所示:

<!-- Main Frame -->
<Grid Grid.Column="1" Margin="10" Name="MainWindowFrameContent">
    <ItemsControl ItemsSource="{Binding Path=MainWindowFrameContent}" >

        <!-- This controls the height automatically of the user control -->
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Columns="1" IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</Grid>

在我的MainWindow.cs的构造函数中,我将窗口的DataContext设置为MainViewModel:

using myProject.ViewModel;

public partial class MainWindow : Window
{
    MainViewModel mMainViewModel;

    public MainWindow()
    {
        InitializeComponent();

        // Initialize MainViewModel and set data context to the VM
        mMainViewModel = new MainViewModel();
        DataContext = mMainViewModel;
    }
}

(我不确定这个下一部分是否是一个可观察的集合,但我已经实现了它似乎运行良好。唯一的缺点是我需要在添加新的之前手动清除ItemsControl用户控件)

我的MainViewModel实现了名为“MainWindowFrameContent”的绑定。我的所有用户控件都在MainViewModel.cs代码中初始化。我为每个UserControl添加了一个ViewModel,并在将UserControl显示到主窗口之前将UserControl的DataContext分配给单个ViewModel。

我的MainViewModel.cs:

public class MainViewModel : ObservableObject
{
    public MainViewModel()
    {
    }

    // This handles adding framework (UI) elements to the main window frame
    ObservableCollection<FrameworkElement> _MainWindowFrameContent = new ObservableCollection<FrameworkElement>();
    public ObservableCollection<FrameworkElement> MainWindowFrameContent
    {
        get
        {
            return _MainWindowFrameContent;
        }
        set
        {
            _MainWindowFrameContent = value;
            RaisePropertyChangedEvent("MainWindowFrameContent");
        }
    }

    // This handles opening a generic user control on the main window
    // The ICommand implementation allows me to bind the command of a button on the main window to displaying a specific page
    public ICommand MainWindowDataEntryView
    {
        get
        {
            return new DelegateCommand(_MainWindowDataEntryView);
        }
    }
    void _MainWindowDataEntryView(object obj)
    {
        DataEntryVM wDataEntryVM = new DataEntryVM();
        DataEntryView wDataEntryView = new DataEntryView();
        wDataEntryView.DataContext = wDataEntryVM;

        MainWindowFrameContent.Clear();
        MainWindowFrameContent.Add(wDataEntryView);
    }
}

然后,您需要确保将ObservableObject.cs作为项目的一部分:

using System.ComponentModel;
public class ObservableObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChangedEvent(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

您需要一个DelegateCommand.cs类作为项目的一部分:

using System;
using System.Windows.Input;
public class DelegateCommand : ICommand
{
    private readonly Action<object> _action;

    public DelegateCommand(Action<object> action)
    {
        _action = action;
    }

    public void Execute(object parameter)
    {
        _action(parameter);
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

#pragma warning disable 67
    public event EventHandler CanExecuteChanged { add { } remove { } }
#pragma warning restore 67
}

所以,这是一个冗长的解释,但是一旦你设置了以前的项目,就可以在MainWindow.xaml中添加一堆按钮,将每个按钮绑定到一个命令,将一个新的UserControl添加到ItemsControl 。当您的UserControl显示时,您可以根据需要添加控件并使用它们。

我希望这有帮助!