【问题标题】:opening the appbar in metro style apps using binding property使用绑定属性在 Metro 风格应用程序中打开 appbar
【发布时间】:2012-09-25 11:58:28
【问题描述】:

我的主页有 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;
    } 

世界视图模型

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 没有弹出。没有绑定错误,所以真的很神秘!

【问题讨论】:

  • 你能发布你的gridview和item点击事件的定义吗?
  • 你可以在你的 xaml 中添加 DataContext 吗?也许你的绑定是错误的。另一方面:我认为你不应该那样做,因为不希望在 UI 中单击时打开应用栏。你想让我做什么? AppBar 将在单击右键或滑动时调用。
  • @Fixus 我已经添加了gridview的定义。而且我认为 SelectionChangedEvent 的工作方式与点击的项目相同吗?我也尝试了右键点击事件,但没有成功。
  • @Raubi 我将相同的绑定放在一个文本块上,只是为了检查绑定是否正在发生并且文本块显示的是真实值。我认为 IsOpen 属性被设置为 true 但 appbar 仍然没有打开......不知道!并且应用栏包含添加和删除等按钮,因此当我选择一个项目时,我希望应用栏立即弹出,以便用户可以删除该项目。我不希望用户每次选择项目然后右键点击......当用户选择项目时,应用栏应该会自动弹出
  • 正常点击(左点击)是否有效?

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


【解决方案1】:

没有办法绑定IsOpen属性according the msdn

注意绑定到IsOpen 属性没有预期的结果 因为PropertyChanged 通知不会在 属性已设置。

【讨论】:

    【解决方案2】:
    <AppBar Opened="AppBar_Opened" IsOpen="{Binding IsAppBarOpen, **Mode=TwoWay**}">
    

    【讨论】:

    • 这是一个很好的建议,但奇怪的是它仍然不起作用! :(
    【解决方案3】:

    这对我有用。我使用 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}">
    

    【讨论】:

      【解决方案4】:

      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 的人,我不建议您进一步朝那个(有罪的)方向前进。

      【讨论】:

        【解决方案5】:

        我遇到了同样的问题,我使用 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);
            }
        }
        

        【讨论】:

          【解决方案6】:

          遇到了同样的问题,通过添加 Closed 事件并从后面的代码更新 ViewModel 来解决它。没有其他办法,因为正如 Roman 指出的那样,双向绑定无法正常工作。

          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# 主视图模型

          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);
            }
          }
          

          【讨论】:

            【解决方案7】:

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

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

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

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

            【讨论】:

              【解决方案8】:

              另一种无需对应用栏关闭事件使用代码隐藏处理程序即可完成这项工作的方法:

              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;
                  }
              

              【讨论】:

                猜你喜欢
                • 2013-04-07
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-11-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多