简体   繁体   English

是运算符在C#中总是结果为false

[英]is operator always results to false in C#

I have this code: 我有以下代码:

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

            return this.changePageCommand;
        }
    }

Whenever I call this particular command, passing a IPageViewModel implementing class, the second parameter for ActionCommand , which is the predicate, always is false. 每当我调用此特定命令时,传递IPageViewModel实现类,即ActionCommand的第二个参数(即谓词)始终为false。 I basically have all the IPageViewModel s in a dictionary. 我基本上在字典中有所有IPageViewModel This is my entire ViewModel class: 这是我的整个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;
        }
    }
}

For some reason, although the parameter implements the IPageViewModel , it always results to false. 出于某种原因,尽管参数实现了IPageViewModel ,但它始终会导致结果为false。 Here's my ActionCommand class: 这是我的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);
        }
    }
}

Here's a use case: 这是一个用例:

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

The thing here is, CanExecute always evaluates to false, hence, the Button click is disable here. 这里的事情是, CanExecute总是计算为false,因此在此禁用了Button单击。 But, I tried replacing the predicate to just true which makes the program work totally as expected. 但是,我尝试将谓词替换为true ,这使程序完全可以按预期运行。 Here's the DashboardViewModel which is what I'm passing to the command here: 这是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();
            }
        }
    }
}

As the parameter is the same to both CanExecute and Execute , the only way for your snippet 由于CanExecuteExecuteparameter相同,因此代码段的唯一方法

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

to not throw an exception in the first assignment (explicit casting) and to yield null as result in the second assignment is, to pass null as parameter. 在第一个赋值中不抛出异常(显式强制转换),并在第二个赋值中产生null作为结果,将null作为参数传递。 So check for null and react appropriatly. 因此,请检查是否为空并做出适当的反应。

Hope this helps. 希望这可以帮助。

Change the xaml of the button the otherway around so the CommandParameter is evaluated before the command. 否则,请更改按钮的xaml,以便在执行命令之前先评估CommandParameter。

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

Also when you change the CommandParameter's binding, you need to manually force the command's CanExecuteChanged evaluation. 同样,在更改CommandParameter的绑定时,还需要手动强制执行命令的CanExecuteChanged评估。

You are probably better off using just the name as the parameter however. 但是,最好只使用名称作为参数。

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

And in the viewmodel make following changes. 并在视图模型中进行以下更改。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM