在XAML中,如何在不使用数据绑定的情况下引用非静态属性?

时间:2017-03-21 17:54:23

标签: c# wpf xaml

我正在使用转换器 -

public class EnumSwitchConverter :  ConverterBase {
    private object
        _On = null,
        _Off = null;

    /// <summary>
    /// Get or Set object returned when parameter is present in value.
    /// </summary>
    public object On {
        get { return this._On; }
        set { this._On = value; }
    }

    /// <summary>
    /// Get or Set object returned when parameter is not present in value.
    /// </summary>
    public object Off {
        get { return this._Off; }
        set { this._Off = value; }
    }

    public override object Convert(
        object value, Type targetType, object parameter, CultureInfo culture ) {
        return ( ( Enum )value ).HasFlag( ( Enum )parameter )
            ? this.On : this.Off;
    }
}

ConverterBase只是一个实现MarkupExtensionIValueConverterIMultiValueConverter的抽象类,因为我厌倦了手动执行此操作。)

我想使用此转换器绑定到Enum属性。如上所述,当enum是指定值时,转换器返回设置为On属性的任何内容,如果不是,则转换器返回设置为Off属性的任何内容。我想将两个不同的命令传递给OnOff属性。在执行操作时,当绑定的枚举与目标值匹配时,该按钮将调用设置为On属性的命令,如果不匹配,该按钮将调用设置为Off属性的命令。

<Button Command="{Binding
    PropertySource.SomeEnumProperty,
    Source={x:Static Application.Current},
    Converter={myConverters:EnumConverter
        On={}, Off={}}
    ConverterParameter={x:Static myEnum:enumValue}/>

我有两个属性可以公开我想要进入On和Off的命令。

public partial class App : Application { 
    /*Stuff*/
    public ICommand onCommand{ get{ return this._onCommand; } }
    public ICommand offCommand{ get{ return this._offCommand; } }
}

我不想做以下事情 -

On={Binding OnCommand, Source={x:Static Application.Current}

首先,OnCommand永远不会改变。其次,On不是依赖属性,所以无论如何我都无法做到。我只想传递OnCommand作为对转换器的On属性的引用。

我如何在转换器中引用命令属性?

1 个答案:

答案 0 :(得分:2)

我可以想到两种方法来做到这一点,另一种方式(加上@ mm8指出的第三种方式):

  1. 使命令成为静态。

    public partial class App : Application { 
        public static ICommand OnCommand { get{ return _onCommand; } }
        public static ICommand OffCommand { get{ return _offCommand; } }
    }
    

    XAML

    <Button 
        Command="{Binding
            PropertySource.SomeEnumProperty,
            Source={x:Static Application.Current},
            Converter={myConverters:EnumConverter
                On={x:Static local:App.OnCommand}, 
                Off={x:Static local:App.OffCommand}}
            ConverterParameter={x:Static myEnum:enumValue}}"
        />
    
  2. 将命令保留为实例属性并写入另一个MarkupExtension

    public class GetInstanceProp : MarkupExtension
    {
        public GetInstanceProp(String propname, Object source)
        {
            _source = source;
            _propName = propname;
        }
    
        private Object _source;
        private String _propName;
    
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var propInfo = _source.GetType().GetProperty(_propName);
    
            return propInfo.GetValue(_source);
        }
    }
    

    XAML

    <Button 
        Command="{Binding
            PropertySource.SomeEnumProperty,
            Source={x:Static Application.Current},
            Converter={myConverters:EnumConverter
                On={local:GetInstanceProp OnCommand, {x:Static local:App.Current}}, 
                Off={local:GetInstanceProp OffCommand, {x:Static local:App.Current}}
            ConverterParameter={x:Static myEnum:enumValue}}"
        />
    

    您需要了解您在此处所做的事情:标记扩展仅在解析XAML时评估一次且仅评估一次。这是标记扩展名。 GetProp将为您提供该属性然后的值。如果它是一个没有setter的命令属性,那就可以了,它在构造函数中初始化,或者第一次任何人调用getter。就是我们来到这里的情况。但很多时候,事实并非如此。

  3. mm8建议的另一个选项是从DependencyObject而不是从MarkupExtension派生您的valueconverter。这意味着您必须在资源中创建它的实例,但这不是世界末日。然后你可以给它可绑定的依赖属性。

    如果你真的厌倦了StaticResource值转换器,你可以编写一个MarkupExtension来返回依赖项对象/值转换器类的实例。 MarkupExtension可以镜像其属性并将值转发给它。但到目前为止,我看不到任何投资回报率。