使用绑定属性在metro风格的应用程序中打开appbar

时间:2012-09-25 11:58:29

标签: c# xaml windows-runtime winrt-xaml

我的主页面有appbar,它在不同的页面上共享。我编写了以下代码,在点击gridview项目时打开appbar。

XAML

<AppBar Opened="AppBar_Opened" IsOpen="{Binding IsAppBarOpen}">

后端

private void Clock_SelectionChanged(object sender, SelectionChangedEventArgs e)
{            
    App.ViewModel.SelectedClock = (Clock)ThemeGridView.SelectedItem;
    App.WorldViewModel.IsAppBarOpen = true;                  
}

 private void ThemeGridView_ItemClick(object sender, ItemClickEventArgs e)
    {
        App.ViewModel.SelectedClock = (Clock)ThemeGridView.SelectedItem;
        App.WorldViewModel.IsAppBarOpen = true;
    } 

WorldViewModel

private bool _IsAppBarOpen;

public bool IsAppBarOpen
{
   get { return _IsAppBarOpen; }
   set { base.SetProperty(ref _IsAppBarOpen, value); }
}

GridView XAML

<GridView
        Grid.Row="1"
        Grid.Column="1"


         x:Name="ThemeGridView"                    
                ItemsSource="{Binding Clocks}" 
                ItemTemplate="{StaticResource WorldClockTemplate}"
                SelectionChanged="Clock_SelectionChanged"
                SelectionMode="None"
                IsItemClickEnabled="True"
                ItemClick="ThemeGridView_ItemClick"
                >
        <GridView.ItemsPanel>
            <ItemsPanelTemplate>
               <WrapGrid />
            </ItemsPanelTemplate>
        </GridView.ItemsPanel>
    </GridView>

但是当我选择gridview项目时,appbar没有弹出。没有绑定错误所以它真的很神秘!

8 个答案:

答案 0 :(得分:3)

无法绑定IsOpen属性according the msdn

  

注意绑定到IsOpen属性没有预期的结果   因为PropertyChanged通知时不会发生   财产设定。

答案 1 :(得分:1)

<AppBar Opened="AppBar_Opened" IsOpen="{Binding IsAppBarOpen, **Mode=TwoWay**}">

答案 2 :(得分:1)

这对我有用。我使用MVVM Light Toolkit。

public bool AppBarIsOpen
{
    get { return this._appBarIsOpen; }

    set
    {
        if (this._appBarIsOpen == value) { return; }

        this._appBarIsOpen = value;
        this.RaisePropertyChanged("AppBarIsOpen"); // without INotifyPropertyChanged it doesn't work
    }
}


<AppBar
    IsSticky="True"
    IsOpen="{Binding Path=AppBarIsOpen, Mode=TwoWay}">

答案 3 :(得分:0)

Roman Weisert的答案正确地指出了它不起作用的可能原因,尽管你也必须像Zack Weiner所说的那样双向绑定(我不确定后者的原因,因为绑定在目标中不起作用无论如何,来源方向)。 AppBar.IsOpen的当前值可能不会被您的视图模型的IsAppBarOpen反映出来。如果是这种情况,并且您尝试更新该值,则可能不会引发PropertyChanged事件,因为您实际上可能没有更新值。相反,您可能只是将值从false设置为false或从true设置为true。除非有实际更改,否则大多数SetProperty方法实现不会引发PropertyChanged事件,并且我认为它们是相同的。

要解决此问题,请考虑按如下方式修改视图模型:

public bool IsAppBarOpen
{
    get { return _IsAppBarOpen; } //changes initiated from UI not reflected
    set //not updated from UI
    {
        _IsAppBarOpen = value;
        base.OnPropertyChanged();
    }
}
bool _IsAppBarOpen;

与视图模型代码的显着区别在于,此处未调用SetProperty,因此即使后备存储等于新引入的值,也会引发PropertyChanged。如果你的基类不同,请注意我的方法有一个带有签名的OnPropertyChanged方法

void OnPropertyChanged( [CallerMemberName] string propertyName = null )

用于举起PropertyChanged事件。

我可以从你使用代码隐藏中看到,你并没有真正关注MVVM。如果您不关心MVVM,那么您可以完全放弃IsAppBarOpen属性并直接设置AppBar.IsOpen。然而,作为一个虔诚地坚持MVVM的人,我不建议你进一步朝着那个(罪恶的)方向前进。

答案 4 :(得分:0)

我遇到了同样的问题并使用Caliburn Micro for WinRT并且这段代码对我有用:

<AppBar IsOpen="{Binding AppBarsOpen}" Name="MainAppBar" Padding="10,0,10,0" AutomationProperties.Name="Bottom App Bar">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="50*" />
            <ColumnDefinition Width="50*" />
        </Grid.ColumnDefinitions>
        <StackPanel x:Name="LeftPanel" Orientation="Horizontal" Grid.Column="0" HorizontalAlignment="Left">
            <Button Name="ShowFlyout"  Style="{StaticResource BookmarksAppBarButtonStyle}" />
        </StackPanel>
        <StackPanel x:Name="RightPanel" Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right">
            <Button Style="{StaticResource SaveAppBarButtonStyle}" />
        </StackPanel>
    </Grid>
</AppBar>

这是ViewModel中的属性:

public bool AppBarsOpen
{
    get { return _appBarsOpen; }
    set
    {
        if (value.Equals(_appBarsOpen)) return;
        _appBarsOpen = value;
        NotifyOfPropertyChange(() => AppBarsOpen);
    }
}

答案 5 :(得分:0)

有同样的问题,通过添加Closed事件并从后面的代码更新ViewModel来解决它。由于TwoWay绑定没有像罗马指出的那样起作用,所以别无他法。

XAML

<AppBar x:Name="BottomAppBar1"
                AutomationProperties.Name="Bottom App Bar"
                Closed="BottomAppBar1_Closed"
                IsOpen="{Binding IsOpen, Mode=TwoWay}"
                IsSticky="True">

C#代码背后

private void BottomAppBar1_Closed(object sender, object e)
{
  MainViewModel vm = this.DataContext as MainViewModel;
  vm.IsOpen = false;
}

C#MainViewModel

public const string IsOpenPropertyName = "IsOpen";

private bool isOpen = false;

/// <summary>
/// Sets and gets the IsOpen property.
/// Changes to that property's value raise the PropertyChanged event. 
/// </summary>
public bool IsOpen
{
  get
  {
    return isOpen;
  }
  set
  {
    RaisePropertyChanging(IsOpenPropertyName);
    isOpen = value;
    RaisePropertyChanged(IsOpenPropertyName);
  }
}

答案 6 :(得分:0)

你应该两种方式绑定IsOpen和IsSticky,否则你会遇到问题,例如必须点击两次取消选择一个项目(一次关闭应用栏和一次取消选择),这也有助于你应用栏表现得更加标准(当选择项目时,将阻止应用栏在点按时弹出)。
要显示应用栏,您需要执行以下操作(顺序很重要):

this.IsAppBarSticky = true;
this.IsAppBarOpen = true;

要隐藏它,请执行以下操作:

this.IsAppBarSticky = false;
this.IsAppBarOpen = false;

答案 7 :(得分:0)

使用此工作的另一种方法,无需为app bar关闭事件使用代码隐藏处理程序:

public class AppBarClosedCommand
{
    public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand),
        typeof(AppBarClosedCommand), new PropertyMetadata(null, CommandPropertyChanged));


    public static void SetCommand(DependencyObject attached, ICommand value)
    {
        attached.SetValue(CommandProperty, value);
    }


    public static ICommand GetCommand(DependencyObject attached)
    {
        return (ICommand)attached.GetValue(CommandProperty);
    }


    private static void CommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // Attach click handler
        (d as AppBar).Closed += AppBar_onClose;
    }


    private static void AppBar_onClose(object sender, object e)
    {
        // Get GridView
        var appBar = (sender as AppBar);


        // Get command
        ICommand command = GetCommand(appBar);


        // Execute command
        command.Execute(e);
    }
}

然后在XAML中你可以使用它:

common:AppBarClosedCommand.Command="{Binding AppBarClosedCommand}"

命令功能如下:

public void OnAppBarClosed()
    {
        AppBarOpen = false;
    }