【问题标题】:Collapse hyperlink when Command.CanExecute returns false当 Command.CanExecute 返回 false 时折叠超链接
【发布时间】:2012-12-04 15:01:43
【问题描述】:

简单的问题是:当超链接的绑定命令 .CanExecute 返回 false 时,如何隐藏超链接?

xaml:

<TextBlock>
    <Hyperlink Command="{Binding IncludesCanExecuteCommand}">Link text</Hyperlink>
</TextBlock>

代码:

...
private ICommand _includesCanExecuteCommand;
....
    _includesCanExecuteCommand = new RelayCommand(ExecuteTheCommand, CanExecuteTheCommand);
....

public ICommand IncludesCanExecuteCommand
{
    get
    {
        return _includesCanExecuteCommand;
    }
}

....

public bool CanExecuteTheCommand()
{
    return BooleanResult();
}

public void ExecuteTheCommand()
{
    DoSomeWork();
}

当 CanExecute() 函数返回 false 时,如何设置文本块/超链接(或运行,如果需要)以使链接折叠?我试过了:

<Hyperlink.Style>
    <Style TargetType="{x:Type Hyperlink}" BasedOn="{StaticResource DefaultHyperlinkStyle}">
        <Setter Property="TextBlock.Visibility" Value="Visible" />
        <Style.Triggers>
            <Trigger Property="IsEnabled" Value="False">
                <Setter Property="TextBlock.Visibility" Value="Collapsed" />
            </Trigger>
        </Style.Triggers>
     </Style>
 </Hyperlink.Style>                        

我还尝试将样式放在文本块上(无法访问超链接)和超链接内的 Run(没有可见性属性)。

感谢所有想法!

【问题讨论】:

    标签: wpf xaml


    【解决方案1】:

    我今天花了很多时间看这个,但在我尝试这个之前没有任何效果。 基本上解决方案是将文本放在超链接内的文本块中,然后使用 BooleanToVisiblityConverter 设置其可见性,因为当超链接被禁用时,内部 TextBlock 将被禁用。

    <UserControl.Resources>
        <converters:BooleanToVisibiltyConverter x:Key="BooleanToVisibiltyConverter" />
    </UserControl.Resources>
    
    <TextBlock >
        <Hyperlink Command="{Binding EditDetailsCommand}">
            <TextBlock
                Visibility="{Binding Path=IsEnabled
                    , RelativeSource={RelativeSource Self}
                    , Mode=OneWay
                    , Converter={StaticResource BooleanToVisibiltyConverter}}">
            Edit Details 
            </TextBlock>
        </Hyperlink>                  
    </TextBlock >
    
    
    public class BooleanToVisibiltyConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                throw new ArgumentNullException("value"); 
    
            if (!(value is bool))
                throw new ArgumentException("Expected type of value must be boolean");
    
            if (parameter != null && !(parameter is Visibility))
                throw new ArgumentException("Expected type of parameter must be Visibility");
    
            Visibility falseVisibility = Visibility.Collapsed;
    
            if (parameter != null)
            {
                falseVisibility = (Visibility)parameter;
    
                if (falseVisibility == Visibility.Visible)
                {
                    throw new ArgumentException("Cannot pass visible to expected false value parameter.");
                }
            }
    
            return (bool)value ? Visibility.Visible : falseVisibility;  
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
                throw new ArgumentNullException("value"); 
    
            if (!(value is Visibility))
                throw new ArgumentException("Expected type of value must be Visibility");
    
            if (value == null)
            {
                throw new ArgumentNullException("value"); 
            }
    
            Visibility v = (Visibility)value;
    
            return v == Visibility.Visible;
        }
    }
    

    【讨论】:

    • 优秀的解决方案。
    【解决方案2】:

    超链接上没有 TextBlock.Visibility 的附加属性。将样式直接放在超链接的包含 TextBlock 中,这应该会解决 Visibility。

    如果没有,则创建一个bool to visibility converter 并在 TextBlock 上设置转换器以获得可见性;并将转换器绑定到 CanExecuteTheCommand 属性。

    需要注意的是,如果没有在 CanExecuteTheCommand 属性上引发 Property Changed 通知,那么转换器只会在第一次加载视图时进行评估;之后,它就会变得陈旧。

    【讨论】:

    • 这里要注意的几点: 1. 样式不能绑定到超链接的 IsEnabled,我认为这是你所得到的; 2. 绑定到 Can.. 方法也使用的另一个属性感觉就像是一种软糖,因为某些东西已经在做这项工作了,但是感谢您的提议。
    • 多次绑定属性不是“忽悠”;这是标准做法。您需要使用布尔到可见性转换器并绑定到确定链接是否可用的任何属性;无论该属性是否也绑定到其他东西。
    • 我明白,“软糖”的感觉是因为我添加代码是为了根据其属性之一设置超链接的样式。但是,感谢您的澄清 - 问题的简单部分的简单答案是“你不能 - 自己做”:)
    【解决方案3】:

    所以这里似乎有两个问题..

    我可能会想在调用后设置一个属性 包括CanExecuteCommand.RaiseCanExecuteChanged() 这将导致命令重新评估其 CanExecuteCommand..

    将超链接放在面板中,然后使用转换器将可见性绑定到 1.) 中的属性,以返回有效的 Visiblility 枚举,例如 Collapsed、Visible 等。

    所以为了清楚起见 - 类似于

    <StackPanel Visibility="{Binding IsHyperlinkVisible, Mode=TwoWay,     Converter=boolToVisibilityConverter}">
      <TextBlock>
        <Hyperlink Command="{Binding WhateverTheHyperlinkDoesCommand}">Link text</Hyperlink>
    </TextBlock>
    </StackPanel>
    

    并且 viewmodel 看起来像这样(如果 viewmodelbase 实现了某个版本的 NotifyPropertyChanged...

     public class ViewModel : NotificationViewModelBase 
     {
            public ViewModel()
            {
                this.WhateverTheHyperlinkDoesCommand =
                    new DelegateCommand<object>(
                        this.ExecuteWhateverTheHyperlinkDoesCommand, this.CanWhateverTheHyperlinkDoesCommand);
            }
    
            private void ExecuteWhateverTheHyperlinkDoesCommand(object arg)
            {
                this.SomeOtherProperty = true;            }
    
            private bool someOtherProperty;
    
            public bool SomeOtherProperty
            {
                get
                {
                    return this.someOtherProperty;
                }
    
                set
                {
                    if (this.ChangeAndRaisePropertyChanged(
                        () => this.SomeOtherProperty, value, ref this.someOtherProperty))
                    {
                        this.WhateverTheHyperlinkDoesCommand.RaiseCanExecuteChanged();
                    }
                }
            }
    
                private bool isHyperlinkProperty;
    
            public bool IsHyperlinkProperty
            {
                get
                {
                    return this.isHyperlinkProperty;
                }
    
                set
                {
                    this.ChangeAndRaisePropertyChanged(() => this.IsHyperlinkProperty, value, ref this.isHyperlinkProperty);
                }
            }
    
            private bool CanWhateverTheHyperlinkDoesCommand(object obj)
            {
                // So based on a certain condition - lets say some other property
    
                if (this.SomeOtherProperty == false)
                {
                    this.IsHyperlinkProperty = true;
                    return false;
                }
    
                this.IsHyperlinkProperty = false;
                return true;
            }
    
            public DelegateCommand<object> WhateverTheHyperlinkDoesCommand { get; set; }
    

    } }

    【讨论】:

    • 不确定我是否理解你的诱惑,你能用代码解释一下吗?
    • 是的,我明白了。这似乎是我试图询问是否可以避免的很多代码,因为超链接已经知道它是否可以执行。不过,感谢您提供清晰的说明。
    【解决方案4】:

    命名超链接也很有效,并为您提供了一些灵活性。另外,您可以使用内置的BooleanToVisibilityConverter

    <UserControl.Resources>
        <BooleanToVisibilityConverterx:Key="BooleanToVisibilityConverter" />
    </UserControl.Resources>
    
    <TextBlock Visibility="{Binding Path=IsEnabled,
                                    ElementName=Linky,
                                    Mode=OneWay,
                                    Converter={StaticResource BooleanToVisibilityConverter}}">>
        <Hyperlink x:Name="Linky" Command="{Binding EditDetailsCommand}">
            <Run Text="Edit Details"/>
        </Hyperlink>                  
    </TextBlock >
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-13
      • 1970-01-01
      • 1970-01-01
      • 2013-08-09
      • 2023-03-05
      • 2014-02-21
      • 1970-01-01
      相关资源
      最近更新 更多