【问题标题】:Windows Phone 8.1 - Menu flyout item click command c#Windows Phone 8.1 - 菜单弹出项单击命令 c#
【发布时间】:2014-09-06 17:21:36
【问题描述】:

我正在为 Windows Phone 8.1 编写应用程序,并且我想在 listView 项目上使用浮出控件。因为我正在尽我最大的努力编写漂亮的应用程序,所以我正在尝试将 MVVM 模式和资源字典与模板中的所有 xaml 一起使用在一页中。 但是,我无法绑定我的 MenuFlyoutItem 命令 - 似乎它没有看到页面的数据上下文,或者它有一些其他数据上下文。这是一些代码:

1) 我的模板在一个单独的资源字典中:

<Grid Margin="0, 0, 0, 10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="4*" />
        </Grid.ColumnDefinitions>

        <Grid.Resources>
            <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
            <converters:EmptyDateConverter x:Key="EmptyDateConverter" />
        </Grid.Resources>

        <i:Interaction.Behaviors>
            <icore:EventTriggerBehavior EventName="Holding">
                <converters:OpenMenuFlyoutAction />
            </icore:EventTriggerBehavior>
        </i:Interaction.Behaviors>

        <FlyoutBase.AttachedFlyout>
            <MenuFlyout>
                <MenuFlyoutItem x:Uid="AddToCalendarMenuItem" Command="{Binding AddToCalendar}" />
            </MenuFlyout>
        </FlyoutBase.AttachedFlyout>

        <Image Grid.Column="0" Source="{Binding ThumbnailUri}"/>
        <StackPanel Grid.Column="1" Orientation="Vertical" Margin="10,0,0,0">
            <TextBlock Text="{Binding Title}" Style="{StaticResource ListItemTitle}"/>
            <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
                <TextBlock x:Uid="DvdReleaseDate" />
                <TextBlock Text="{Binding DvdRelease, Converter={StaticResource EmptyDateConverter}}" />
            </StackPanel>
        </StackPanel>
    </Grid>

2) 这是列表视图:

<ListView Grid.Row="1" x:Name="SearchListView"
                  ItemsSource="{Binding SearchList}"
                  ItemTemplate="{StaticResource SearchListTemplate}" SelectionChanged="NavigateToMovieDetails"  />

我的 ViewModel 是 app.xaml.cs 中的一种静态单例

我尝试在 xaml 中创建 VM 的新实例,但没有成功 - 也许我做错了。

非常感谢您的帮助!提前致谢。

最好的问候, 罗马

【问题讨论】:

  • 如果 Grid 是您的 &lt;ItemTemplate&gt; 并且您以这种方式绑定该 Command,这意味着您将需要为您放入 ViewModel 中的每个模型提供一个 Command。所以无论你把“DvdRelease”放在哪里,也应该有一个命令。
  • 谢谢,我会尝试,我认为虽然它破坏了 MVVM 设计 - 逻辑应该在 viewModel 中而不是在模型中
  • 如果在ViewModel中就更好了。如果你想以这种方式实现它,我有一个很好的教程来说明如何做到这一点:stackoverflow.com/questions/25613212/…
  • 非常感谢 - 它有效并且不违反 MVVM 原则!
  • Np,我会将教程链接为答案,以便人们更好地看到它。请将其标记为解决方案,因此它不会显示在我的未回答页面上:)

标签: c# xaml windows-phone-8 mvvm


【解决方案1】:

如果您坚持使用 &lt;ItemTemplate&gt;,则您的 ViewModel 中的每个模型都必须有一个命令,这并不理想。

要设置单个命令并拥有一个命令参数,请参阅此 SO 教程,我在这里输入的代码太多:

Implement a ViewModel Single Command with CommandParamater

【讨论】:

    【解决方案2】:

    @Chubosaurus Software 按照你的方法我想出了这个。

    这是一个 ListView 绑定到一个待办事项列表,该列表放置在一个 DataTemplate 中,其中包含一个 TextBlock 具有一个 MenuFlyout 以显示编辑、删除上下文菜单之类的东西。

    将视图模型中的命令绑定到MenuFlyoutItem 的关键是给ListView 一个名称,并使用Command 中的ElementName 属性进行元素绑定以指向ListView 的名称。要访问我们视图模型中的命令,我们必须通过 ListView 的 DataContext 并将其绑定到其上的命令,因为 MenuFlyoutItemDataContextItemsSource 中的一个项目

    MainPage.xaml

    <Page
        x:Class="UWA.MenuFlyout.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:UWA.MenuFlyout"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:vm="using:UWA.MenuFlyout.ViewModels"
        xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
        xmlns:core="using:Microsoft.Xaml.Interactions.Core"
        xmlns:common="using:UWA.MenuFlyout.Core"
        mc:Ignorable="d"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    
        <Grid Margin="24,24">
            <ListView x:Name="Todos" ItemsSource="{Binding Todos}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Action}">
                            <FlyoutBase.AttachedFlyout>
                                <MenuFlyout>
                                    <MenuFlyoutItem Text="edit" 
                                                    Command="{Binding ElementName=Todos, Path=DataContext.EditTodo}"
                                                    CommandParameter="{Binding}"/>
                                    <MenuFlyoutItem Text="delete" 
                                                    Command="{Binding ElementName=Todos, Path=DataContext.DeleteTodo}"
                                                    CommandParameter="{Binding}"/>
                                </MenuFlyout>
                            </FlyoutBase.AttachedFlyout>
    
                            <interactivity:Interaction.Behaviors>
                                <core:EventTriggerBehavior EventName="Holding">
                                    <common:OpenMenuFlyoutAction/>
                                </core:EventTriggerBehavior>
                                <core:EventTriggerBehavior EventName="RightTapped">
                                    <common:OpenMenuFlyoutAction/>
                                </core:EventTriggerBehavior>
                            </interactivity:Interaction.Behaviors>
                        </TextBlock>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Grid>
    </Page>
    

    MainPage.xaml.cs 是设置 MainPage 的 DataContext 的位置。

    namespace UWA.MenuFlyout
    {
        using UWA.MenuFlyout.ViewModels;
        using Windows.UI.Xaml.Controls;
        using Windows.UI.Xaml.Navigation;
    
        /// <summary>
        /// An empty page that can be used on its own or navigated to within a Frame.
        /// </summary>
        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
    
                this.NavigationCacheMode = NavigationCacheMode.Required;
                this.DataContext = new MainViewModel();
            }
    
            /// <summary>
            /// Invoked when this page is about to be displayed in a Frame.
            /// </summary>
            /// <param name="e">Event data that describes how this page was reached.
            /// This parameter is typically used to configure the page.</param>
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                // TODO: Prepare page for display here.
    
                // TODO: If your application contains multiple pages, ensure that you are
                // handling the hardware Back button by registering for the
                // Windows.Phone.UI.Input.HardwareButtons.BackPressed event.
                // If you are using the NavigationHelper provided by some templates,
                // this event is handled for you.
            }
        }
    }
    

    包含 ObservableCollection 类型的 Todos 以及 EditTodo 和 DeleteTodo 命令的 MainViewModel.cs。

    namespace UWA.MenuFlyout.ViewModels
    {
        using System.Collections.ObjectModel;
        using System.Windows.Input;
        using UWA.MenuFlyout.Core;
        using UWA.MenuFlyout.Models;
    
        public class MainViewModel : BaseViewModel
        {
            private ICommand editTodo;
    
            private ICommand deleteTodo;
    
            public MainViewModel()
            {
                this.Todos = new ObservableCollection<TodoModel>
                {
                    new TodoModel { Id = 1, Action = "Buy Milk", IsDone = true },
                    new TodoModel { Id = 2, Action = "Buy Groceries", IsDone = false }
                };
            }
    
            public ObservableCollection<TodoModel> Todos { get; set; }
    
            public ICommand EditTodo
            {
                get
                {
                    if (this.editTodo == null)
                    {
                        this.editTodo = new RelayCommand(this.OnEditTodo);
                    }
    
                    return this.editTodo;
                }
            }
    
            public ICommand DeleteTodo
            {
                get
                {
                    if (this.deleteTodo == null)
                    {
                        this.deleteTodo = new RelayCommand(this.OnDeleteTodo);
                    }
    
                    return this.deleteTodo;
                }
            }
    
            public void OnEditTodo(object parameter)
            {
                // perform edit here
                var todo = parameter as TodoModel;
            }
    
            public void OnDeleteTodo(object parameter)
            {
                // perform delete here
                var todo = parameter as TodoModel;
            }
        }
    }
    

    模型

    namespace UWA.MenuFlyout.Models
    {
        public class TodoModel
        {
            public int Id { get; set; }
    
            public string Action { get; set; }
    
            public bool IsDone { get; set; }
        }
    }
    

    实现 INotifyPropertyChanged 的​​ BaseViewModel。

    namespace UWA.MenuFlyout.Core
    {
        using System.ComponentModel;
        using System.Runtime.CompilerServices;
    
        public class BaseViewModel : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            public virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
            {
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    }
    

    一个简单的 ICommand 实现。

    namespace UWA.MenuFlyout.Core
    {
        using System;
        using System.Windows.Input;
    
        public class RelayCommand : ICommand
        {
            private Action<object> action;
    
            public RelayCommand(Action<object> action)
            {
                this.action = action;
            }
    
            public event EventHandler CanExecuteChanged;
    
            public bool CanExecute(object parameter)
            {
                return true;
            }
    
            public void Execute(object parameter)
            {
                this.action(parameter);
            }
        }
    }
    

    实现DependencyObject和IAction的OpenMenuFlyoutAction,通过IAction接口的Execute方法打开MenuFlyout。

    namespace UWA.MenuFlyout.Core
    {
        using Microsoft.Xaml.Interactivity;
        using Windows.UI.Xaml;
        using Windows.UI.Xaml.Controls.Primitives;
    
        public class OpenMenuFlyoutAction : DependencyObject, IAction
        {
            public object Execute(object sender, object parameter)
            {
                var frameworkElement = sender as FrameworkElement;
                var flyoutBase = FlyoutBase.GetAttachedFlyout(frameworkElement);
                flyoutBase.ShowAt(frameworkElement);
    
                return null;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多