1
我有一个Windows.UI.Xaml.Controls.ContentDialog
的问题。当System.Windows.Input.ICommand.CanExecute
返回false
时,我想禁用它的主键。但它似乎ContentDialog
不订阅ICommand.CanExecuteChanged
事件。我不知道为什么。这是我的代码:ContentDialog不订阅ICommand.CanExecuteChanged
NewTracingDialog.xaml
<ContentDialog
x:Class="RouterTracer.NewTracingDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:RouterTracer"
xmlns:model="using:RouterTracer.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="NEW TRACING"
PrimaryButtonText="trace"
SecondaryButtonText="cancel"
PrimaryButtonCommand="{Binding}"
d:DataContext="{d:DesignInstance Type=model:NewTracingViewModel}">
<StackPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<TextBox Name="destinationHost" Header="Destination Host" Text="{Binding Host, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Name="port" Header="UDP Port" InputScope="Number" Text="{Binding Port, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Name="hopLimit" Header="Hop Limit" InputScope="Number" Text="{Binding HopLimit, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</ContentDialog>
NewTracingViewModel.cs
//-----------------------------------------------------------------------
// <copyright file="NewTracingViewModel.cs">
// Copyright (c) Putta Khunchalee.
// </copyright>
// <author>Putta Khunchalee</author>
//-----------------------------------------------------------------------
namespace RouterTracer.ViewModels
{
using System;
/// <summary>
/// View model for new tracing dialog.
/// </summary>
public sealed class NewTracingViewModel : ExecutableViewModel
{
private byte hopLimit;
private string host;
private ushort port;
/// <summary>
/// Initialize a new instance of the <see cref="NewTracingViewModel"/> class.
/// </summary>
public NewTracingViewModel()
{
}
/// <summary>
/// Gets or sets TTL or Hop Limit.
/// </summary>
/// <value>
/// TTL or Hop Limit.
/// </value>
public byte HopLimit
{
get { return this.hopLimit; }
set { this.SetProperty(ref this.hopLimit, value, "HopLimit"); }
}
/// <summary>
/// Gets or sets destination host.
/// </summary>
/// <value>
/// Hestination host.
/// </value>
public string Host
{
get { return this.host; }
set { this.SetProperty(ref this.host, value, "Host"); }
}
/// <summary>
/// Gets or sets destination port.
/// </summary>
/// <value>
/// Destination port.
/// </value>
public ushort Port
{
get { return this.port; }
set { this.SetProperty(ref this.port, value, "Port"); }
}
/// <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 <c>null</c>.
/// </param>
public override void Execute(object parameter)
{
// This method get execute normally.
}
/// <summary>
/// Validate all properties to determine executable status.
/// </summary>
/// <returns>
/// <c>true</c> if instance can be execute; otherwise <c>false</c>.
/// </returns>
protected override bool ValidateProperties()
{
if (this.hopLimit == 0)
{
return false;
}
if (string.IsNullOrWhiteSpace(this.host))
{
return false;
}
if (this.port == 0)
{
return false;
}
return true;
}
}
}
ExecutableViewModel.cs
//-----------------------------------------------------------------------
// <copyright file="ExecutableViewModel.cs">
// Copyright (c) Putta Khunchalee.
// </copyright>
// <author>Putta Khunchalee</author>
//-----------------------------------------------------------------------
namespace RouterTracer.ViewModels
{
using System;
using System.Windows.Input;
/// <summary>
/// Base class for all View Model that executable via <see cref="ICommand"/>.
/// </summary>
public abstract class ExecutableViewModel : ViewModel, ICommand
{
private bool canExecute;
/// <summary>
/// Initialize a new instance of the <see cref="ExecutableViewModel"/> class.
/// </summary>
protected ExecutableViewModel()
{
}
/// <summary>
/// Occurs when changes occur that affect whether or not the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged;
/// <summary>
/// Defines the method that determines whether the command can execute in its current state.
/// </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 <c>null</c>.
/// </param>
/// <returns>
/// <c>true</c> if this command can be executed; otherwise, <c>false</c>.
/// </returns>
public bool CanExecute(object parameter)
{
return this.canExecute;
}
/// <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 <c>null</c>.
/// </param>
public abstract void Execute(object parameter);
/// <summary>
/// Invoked when status of <see cref="CanExecute(object)"/> has changed.
/// </summary>
protected virtual void OnCanExecuteChanged()
{
var handlers = this.CanExecuteChanged;
if (handlers != null)
{
handlers(this, EventArgs.Empty);
}
}
/// <summary>
/// Invoked when value of model's property has been changed.
/// </summary>
/// <param name="name">
/// Name of the property that value has changed.
/// </param>
protected override void OnPropertyChanged(string name)
{
base.OnPropertyChanged(name);
this.UpdateCanExecuteFlag(ValidateProperties());
}
/// <summary>
/// Validate all properties to determine executable status.
/// </summary>
/// <returns>
/// <c>true</c> if instance can be execute; otherwise <c>false</c>.
/// </returns>
protected abstract bool ValidateProperties();
/// <summary>
/// Update status of <see cref="CanExecute(object)"/>.
/// </summary>
/// <param name="canExecute">
/// <c>true</c> if instance can be execute; otherwise <c>false</c>.
/// </param>
private void UpdateCanExecuteFlag(bool canExecute)
{
if (this.canExecute == canExecute)
{
return;
}
this.canExecute = canExecute;
this.OnCanExecuteChanged();
}
}
}
个
ViewModel.cs
//-----------------------------------------------------------------------
// <copyright file="ViewModel.cs">
// Copyright (c) Putta Khunchalee.
// </copyright>
// <author>Putta Khunchalee</author>
//-----------------------------------------------------------------------
namespace RouterTracer.ViewModels
{
using System.ComponentModel;
/// <summary>
/// Base class for all View Model.
/// </summary>
public abstract class ViewModel : INotifyPropertyChanged
{
/// <summary>
/// Initialize a new instance of the <see cref="ViewModel"/> class.
/// </summary>
protected ViewModel()
{
}
/// <summary>
/// Raise when value of model's property has been changed.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Invoked when value of model's property has been changed.
/// </summary>
/// <param name="name">
/// Name of the property that value has changed.
/// </param>
protected virtual void OnPropertyChanged(string name)
{
var handlers = this.PropertyChanged;
if (handlers != null)
{
handlers(this, new PropertyChangedEventArgs(name));
}
}
/// <summary>
/// Change the value of the field that is property backed.
/// </summary>
/// <typeparam name="T">
/// Type of the field.
/// </typeparam>
/// <param name="field">
/// Field to change value.
/// </param>
/// <param name="value">
/// The new value.
/// </param>
/// <param name="name">
/// Name of backed property.
/// </param>
/// <returns>
/// <c>true</c> when value has been changed; otherwise <c>false</c>.
/// </returns>
protected bool SetProperty<T>(ref T field, T value, string name)
{
T previousValue;
// Check to see if value change is neccessary.
if (object.Equals(field, value))
{
return false;
}
// Change value.
previousValue = field;
field = value;
this.OnPropertyChanged(name);
return true;
}
}
}
对不起长码。谢谢。