Binding Command of Button in AppBar does not work

只谈情不闲聊 提交于 2019-12-10 17:15:01

问题


Why does the Command in the following example not execute?

I have a named Page with an AppBar and a Button in it:

   <Page
    x:Class="App13.MainPage"
    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"
    mc:Ignorable="d" 
    x:Name="myPage"
    >
    <Page.BottomAppBar>
        <AppBar>
           <Button Content="OK" Command="{Binding OkCommand, ElementName=myPage}" />
        </AppBar>
    </Page.BottomAppBar>
</Page>

The Command "OkCommand" is defined in the code-behind like this (using MVVM light framework):

public RelayCommand OkCommand
{
    get
    {
        return m_OkCommand
            ?? (m_OkCommand = new RelayCommand(
                                  async () =>
                                  {
                                      await new MessageDialog("OkCommand").ShowAsync();
                                  }));
    }
}

There are no binding-errors nor any other hints in the output-window that give me an idea why this does not work. (Aside: if the button is placed outside the AppBar, everything works fine)

Does anyone have an idea what is wrong here?


回答1:


There should be no reason for the command binding not working for a button in AppBar if it works for a button elsewhere on the page.

I suspect the problem is related to how DataContext is set. You should have it set at the page level instead of lower in the control tree. All the other buttons are inside the top content control of the page while the AppBar is outside of it causing the binding not to work if DataContext is set at the top content control or below.

You can try it with the following working example:

MainPage.xaml:

<common:LayoutAwarePage
    x:Class="App16.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App16"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:common="using:App16.Common"
    x:Name="MyPageName"
    mc:Ignorable="d">

    <StackPanel x:Name="MainGrid" Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Button Content="Ok" Command="{Binding OkCommand}" />
    </StackPanel>

    <Page.BottomAppBar>
        <AppBar x:Name="bottomAppBar" Padding="10,10,10,10"  >
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                <Button Style="{StaticResource SkipBackAppBarButtonStyle}" Command="{Binding OkCommand}" >
                </Button>
            </StackPanel>
        </AppBar>
    </Page.BottomAppBar>
</common:LayoutAwarePage>

ViewModel.cs:

public class ViewModel
{
    private RelayCommand _okCommand;
    public RelayCommand OkCommand
    {
        get
        {
            return _okCommand
                ?? (_okCommand = new RelayCommand(
                                      async _ =>
                                      {
                                          await new MessageDialog("OkCommand").ShowAsync();
                                      }));
        }
    }
}

MainPage.xaml.cs:

public sealed partial class MainPage : LayoutAwarePage
{
    public MainPage()
    {
        this.InitializeComponent();
        DataContext = new ViewModel();
    }
}



回答2:


I know this question is for Windows RT/8, however I ran into this same problem with Universal Apps (UWP) and I found the solution using the new {x:Bind}. Note, by default x:Bind will map to OneTime instead of {Binding} where it was OneWay.

I found this pattern while watching one of the MSDN Windows 10 Developer videos on the new XAML Bind.

Modify YourPage.cs

public sealed partial class YourPage : Page
{
    public ViewModels.YourPageViewModel ViewModel { get; set; }

    public YourPage()
    {
        this.InitializeComponent();

        if (DesignMode.DesignModeEnabled) return;

        this.DataContextChanged += (s, e) =>
        {
            ViewModel = DataContext as ViewModels.YourPageViewModel;
        };
    }
}

Modify YourPageViewModel.cs

public class YourPageViewModel : ViewModelBase
{
    private ICommand newFunctionCommand;
    public ICommand NewFunctionCommand { get { return newFunctionCommand; } }

    public YourPageViewModel()
    {
        if (DesignMode.DesignModeEnabled) return;

        if (newFunctionCommand == null)
            newFunctionCommand = new ICommand(new Action(NewFunction));
    }

    protected void NewFunction()
    {

    }
}

Modify YourPage.xaml

<Page.DataContext>
    <vm:YourViewModel x:Name="YourVM" />
</Page.DataContext>

<Page.BottomAppBar>
    <CommandBar ClosedDisplayMode="Compact">
        <AppBarButton x:Name="AddAppBarButton" IsCompact="True"
                      Label="New" Icon="Add"
                      Command="{x:Bind ViewModel.NewFunctionCommand, Mode=OneWay}" />
    </CommandBar>
</Page.BottomAppBar>


来源:https://stackoverflow.com/questions/14365407/binding-command-of-button-in-appbar-does-not-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!