运算符在C#中始终为false

时间:2016-12-08 11:14:38

标签: c# wpf linq

我有这段代码:

    public ICommand ChangePageCommand
    {
        get
        {
            if (this.changePageCommand == null)
            {
                this.changePageCommand = new ActionCommand(
                    parameter => {
                            this.ChangeViewModel((IPageViewModel)parameter);
                        },
                    parameter => parameter is IPageViewModel);
            }

            return this.changePageCommand;
        }
    }

每当我调用此特定命令并传递IPageViewModel实现类时,ActionCommand的第二个参数(谓词)始终为false。我基本上把所有IPageViewModel都放在字典里。这是我的整个ViewModel类:

using VexLibrary.Windows;
using System.Windows.Input;
using System.Collections.Generic;
using VexLibrary.DesktopClient.ViewModels;
using System.Linq;

namespace VexLibrary.DesktopClient.ViewModels
{
    class ApplicationViewModel : ViewModel
    {
        private ICommand changePageCommand;
        private IPageViewModel currentPageViewModel;
        private Dictionary<string, IPageViewModel> pageViewModels;

        public ApplicationViewModel()
        {
            this.PageViewModels.Add("Dashboard", new DashboardViewModel(this));
            this.PageViewModels.Add("Statistics", new StatisticsViewModel());

            this.CurrentPageViewModel = this.PageViewModels["Dashboard"];
        }

        public ICommand ChangePageCommand
        {
            get
            {
                if (this.changePageCommand == null)
                {
                    this.changePageCommand = new ActionCommand(
                        parameter => {
                                this.ChangeViewModel((IPageViewModel)parameter);
                            },
                        parameter => parameter is IPageViewModel);
                }

                return this.changePageCommand;
            }
        }



        public IPageViewModel CurrentPageViewModel
        {
            get
            {
                return this.currentPageViewModel;
            }
            set
            {
                if (this.currentPageViewModel != value)
                {
                    this.currentPageViewModel = value;
                    NotifyPropertyChanged();
                }
            }
        }

        public Dictionary<string, IPageViewModel> PageViewModels
        {
            get
            {
                if (this.pageViewModels == null)
                    this.pageViewModels = new Dictionary<string, IPageViewModel>();

                return this.pageViewModels;
            }
        }


        public void ChangeViewModel(IPageViewModel viewModel)
        {
            this.CurrentPageViewModel = this.pageViewModels.FirstOrDefault(element => element.Value == viewModel).Value;
        }
    }
}

出于某种原因,虽然参数实现了IPageViewModel,但它总是会导致错误。这是我的ActionCommand课程:

using System;
using System.Windows.Input;

namespace VexLibrary.Windows
{
    public sealed class ActionCommand : ICommand
    {
        private readonly Action<Object> action;
        private readonly Predicate<Object> predicate;
        public event EventHandler CanExecuteChanged;

        /// <summary>
        /// Initializes a new instance of the <see cref="ActionCommand"/> class.
        /// </summary>
        /// <param name="action">The <see cref="Action"/> delegate to wrap.</param>
        public ActionCommand(Action<Object> action) : this(action, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActionCommand"/> class.
        /// </summary>
        /// <param name="action">The <see cref="Action"/> delegate to wrap.</param>
        /// <param name="predicate">The <see cref="Predicate{Object}"/> that determines whether the action delegate may be invoked.</param>
        public ActionCommand(Action<Object> action, Predicate<Object> predicate)
        {
            if (action == null)
            {
                throw new ArgumentNullException("action", "You must specify an Action<T>.");
            }

            this.action = action;
            this.predicate = predicate;
        }

        /// <summary>
        /// Defines the method that determines whether the command can execute in its current state.
        /// </summary>
        /// <returns>
        /// true if this command can be executed; otherwise, false.
        /// </returns>
        /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
        public bool CanExecute(object parameter)
        {
            if (predicate == null)
            {
                return true;
            }
            return predicate(parameter);
        }

        /// <summary>
        /// Defines the method to be called when the command is invoked.
        /// </summary>
        /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
        public void Execute(object parameter)
        {
            action(parameter);
        }

        /// <summary>
        /// Executes the action delegate without any parameters.
        /// </summary>
        public void Execute()
        {
            Execute(null);
        }
    }
}

这是一个用例:

                        <Button Command="{Binding ChangePageCommand}"  CommandParameter="{Binding PageViewModels[Dashboard]}">
                            <TextBlock Style="{StaticResource TitleBarIcon}" Text="&#xE10F;" />
                        </Button>

这里的事情是,CanExecute总是计算为false,因此,在这里禁用Button click。但是,我尝试将谓词替换为true,这使得程序完全按预期工作。这是我在这里传递给命令的DashboardViewModel:

using VexLibrary.Windows;
using System.Windows.Input;

namespace VexLibrary.DesktopClient.ViewModels
{
    class DashboardViewModel : ViewModel, IPageViewModel
    {
        private string name = "Dashboard";
        private ApplicationViewModel parentViewModel;
        private ICommand statisticsPageCommand;

        public DashboardViewModel(ApplicationViewModel parentViewModel)
        {
            this.parentViewModel = parentViewModel;
        }

        public ICommand StatisticsPageCommand
        {
            get
            {
                return new ActionCommand(
                    parameter => this.parentViewModel.ChangeViewModel(this.parentViewModel.PageViewModels["Statistics"])
                );
            }
        }

        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                this.name = value;
                NotifyPropertyChanged();
            }
        }
    }
}

2 个答案:

答案 0 :(得分:2)

由于parameterCanExecuteExecute相同,因此您的代码段的唯一方式

this.changePageCommand = new ActionCommand(
  parameter => { this.ChangeViewModel((IPageViewModel)parameter); },
  parameter => parameter is IPageViewModel);

不在第一个赋值中抛出异常(显式转换)并在第二个赋值中产生null,以传递null作为参数。所以检查null并适当地做出反应。

希望这有帮助。

答案 1 :(得分:1)

改变按钮的xaml,以便在命令之前评估CommandParameter。

<Button CommandParameter="{Binding PageViewModels[Dashboard]}" Command="{Binding ChangePageCommand}">
    <TextBlock Style="{StaticResource TitleBarIcon}" Text="&#xE10F;" />
</Button>

同样,当您更改CommandParameter的绑定时,您需要手动强制执行命令的CanExecuteChanged评估。

然而,最好只使用名称作为参数。

<Button Command="{Binding ChangePageCommand}" CommandParameter="Dashboard">
    <TextBlock Style="{StaticResource TitleBarIcon}" Text="&#xE10F;" />
</Button>

并在viewmodel中进行以下更改。

public ICommand ChangePageCommand
{
    get
    {
        return new Command(
                parameter => { this.ChangeViewModel(parameter as string); },
                parameter =>
                    {
                        var str = parameter as string;
                        return !string.IsNullOrEmpty(str) && this.PageViewModels.ContainsKey(str);
                    });
    }
}

public void ChangeViewModel(string viewName)
{
    this.CurrentPageViewModel = this.pageViewModels.FirstOrDefault(element => element.Key == viewName).Value;
}