【问题标题】:How to update Source property of a frame by clicking only one button from user control?如何通过仅单击用户控件中的一个按钮来更新框架的 Source 属性?
【发布时间】:2011-09-01 02:13:37
【问题描述】:

我想了解如何根据点击次数仅单击一个“下一步”按钮来更新源属性,并能够在每次单击该按钮时将不同的页面加载到框架中。任何建议都非常感谢!提前谢谢你。

主窗口代码:

<Grid x:Name="LayoutRoot">
    <Frame Content="Frame" Source="/WpfApplication1;component/Page1.xaml"/>
    <local:NavUserControl HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
</Grid>

包含按钮的用户控件:

<StackPanel x:Name="LayoutRoot" Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,20">
    <Button Content="Back" HorizontalAlignment="Left" Width="75"/>
    <Button Content="Next" HorizontalAlignment="Left" Width="75" />
</StackPanel>

【问题讨论】:

    标签: wpf binding frame


    【解决方案1】:

    在您的 NavUserControl 中,我会为下一个和后退按钮连接事件或命令(或两者兼而有之)。然后您可以从 MainWindow 中访问它们并将适当的值设置到 Source 属性中。

    如果你走事件路线,附加到事件上并直接设置源。

    如果您走命令路线,请在您的视图模型中设置一个命令,将其绑定到用户控件,然后将 Source 属性绑定到您的视图模型中的另一个值。

    编辑:根据 OP 的要求添加一些代码。请记住,这并不是最佳实践。只是一些例子。

    事件路线应该是最简单的。你已经知道如何做到这一点,我想。只需添加:

    public event EventHandler BackClicked;
    public event EventHandler NextClicked;
    
    private void Back_Click(object sender, RoutedEventArgs e)
    {
        BackClicked(sender, e);
    }
    
    private void Next_Click(object sender, RoutedEventArgs e)
    {
        NextClicked(sender, e);
    }
    

    事件到您的 NavUserControl。然后将您的 XAML 更改为:

    <StackPanel x:Name="LayoutRoot" Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,20">    
        <Button Content="Back" HorizontalAlignment="Left" Width="75" Click="Back_Click" />    
        <Button Content="Next" HorizontalAlignment="Left" Width="75" Click="Next_Click" />
    </StackPanel>
    

    现在在您的 MainWindow.xaml.cs 文件中,添加:

    private void BackClicked(object sender, EventArgs e)
    {
        Uri source = // Whatever your business logic is to determine the previous page;
        _Frame.Source = source;
    }
    
    private void NextClicked(object sender, EventArgs e)
    {
        Uri source = // Whatever your business logic is to determine the next page;
        _Frame.Source = source;
    }
    

    并将 MainWindow XAML 更改为:

    <Grid x:Name="LayoutRoot">
        <Frame x:Name="_Frame" Content="Frame" 
               Source="/WpfApplication1;component/Page1.xaml"/>
        <local:NavUserControl HorizontalAlignment="Center" VerticalAlignment="Bottom" 
                              BackClicked="BackClicked" NextClicked="NextClicked" />
    </Grid>
    

    走命令路线需要更多的架构,但更干净。我建议使用您最喜欢的 MVVM 工具包。我最喜欢的是MVVMLight,所以我将在这个例子中使用它。

    创建一个 ViewModel 类,如下所示:

    public class ViewModel : GalaSoft.MvvmLight.ViewModelBase
    {
        private Uri _Source;
        public Uri Source
        {
            get { return _Source; }
            set
            {
                if (_Source != value)
                {
                    _Source = value;
                    RaisePropertyChanged("Source");
                }
            }
        }
    
    
    
        private GalaSoft.MvvmLight.Command.RelayCommand _BackCommand;
        public ICommand BackCommand
        {
            get
            {
                if (_BackCommand == null)
                {
                    _BackCommand = new GalaSoft.MvvmLight.Command.RelayCommand(() =>
                    {
                        Uri source = // Whatever your business logic is to determine the previous page
                        Source = source;
                    });
                }
                return _BackCommand;
            }
        }
    
        private GalaSoft.MvvmLight.Command.RelayCommand _NextCommand;
        public ICommand NextCommand
        {
            get
            {
                if (_NextCommand == null)
                {
                    _NextCommand = new GalaSoft.MvvmLight.Command.RelayCommand(() =>
                    {
                        Uri source = // Whatever your business logic is to determine the next page
                        Source = source;
                    });
                }
                return _NextCommand;
            }
        }
    }
    

    在 MainWindow.xaml.cs 中,创建此类的实例并将 DataContext 属性设置为该实例。然后设置你的绑定:

    <Grid x:Name="LayoutRoot">    
        <Frame Content="Frame" Source="{Binding Source}"/>    
        <local:NavUserControl HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
    </Grid>
    

    <StackPanel x:Name="LayoutRoot" Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,20">    
        <Button Content="Back" HorizontalAlignment="Left" Width="75" Command="{Binding BackCommand}"/>    
        <Button Content="Next" HorizontalAlignment="Left" Width="75" Command="{Binding NextCommand}" />
    </StackPanel>
    

    绑定示例是非常简单的 MVVM 样式 WPF。我建议您走那条路,如果您需要更多帮助,请阅读 WPF 中的 MVVM。以教程和书籍的形式提供大量资源。 Searching here on SO 也有很大帮助。

    再次编辑:

    将您的构造函数更改为:

    public MainWindow()
    {
        this.InitializeComponent();
    
        // Insert code required on object creation below this point.
        DataContext = new ViewModel();
    }
    

    【讨论】:

    • 感谢您的提示。很高兴在工作示例中看到这一点。
    • 您对哪个感兴趣?基于事件还是基于命令?还是两者兼而有之?
    • 我想学习这两种方法。不过,我不想打扰你太多。
    • 我添加了很多示例代码。正如我在编辑中所说,请记住,这不是最佳实践,只是一个示例。
    • 蒂姆,非常感谢您对样品的详细解释。这对我学习 WPF 有很大的帮助。我尝试了事件路线,它对我来说非常有效。我也会尝试命令路由。
    【解决方案2】:

    创建一个实现NextPageCommandPreviousPageCommand 命令的PageViewModel 类,它们分别引发UserNavigatedToNextPageUserNavigatedToPreviousPage 事件。为简单起见,还让它们公开PageViewModel 类型的NextPagePreviousPage 属性。为每个页面创建PageViewModel 的子类。

    为拥有的UserControl 创建一个视图模型类,该类公开PageViewModel 类型的CurrentPage 属性。创建所有PageViewModel 对象并在每个对象上设置NextPagePreviousPage。为这些对象上的导航事件添加处理程序,如下所示:

    public void Page_UserNavigatedToNextPage(object sender, EventArgs e)
    {
       if (sender == CurrentPage && CurrentPage.NextPage != null)
       {
          CurrentPage = CurrentPage.NextPage;
       }
    }
    

    假设您已经实现了属性更改通知,现在每当当前页面的NextPageCommandPreviousPageCommand 执行时,CurrentPage 属性将被更新并反映在 UI 中。如果您已经为每种页面视图模型类型创建了数据模板,那么您只需要

    <ContentPresenter Content="{Binding CurrentPage}"/>
    

    在您的用户控制中,一切顺利。

    如果 Next/Previous 按钮在您的控件中,而不是在页面中,则在主视图模型中实现暴露 CurrentPage.NextPageCommandCurrentPage.PreviousPageCommand 的属性,并将按钮绑定到它们。

    【讨论】:

    • NextPageCommand 和 PreviousPageCommand 应该是什么样子的?可以说,我有 10 页,只有两个按钮可以浏览。我应该用柜台做还是有其他方法?代码 sn-ps 将有很大帮助。再次感谢您。
    • 他们是RelayCommands。 (查看 Josh Smith 的模型/视图/视图模型文章以获取 RelayCommand 类的示例实现。)NextPageCommand 在执行时实际上所做的就是引发 UserNavigatedToNextPage 事件。用户控件的视图模型使用我在上面发布的代码处理事件。页面视图模型是(双)链表中的节点。逐页导航只是遍历列表,因此不需要计数器或索引,只需CurrentPage = CurrentPage.NextPageCurrentPage = CurrentPage.PreviousPage
    • 感谢您提供的信息。这是一种有趣的方法。我需要努力。
    猜你喜欢
    • 2016-03-08
    • 1970-01-01
    • 2021-05-29
    • 2018-06-28
    • 2017-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多