嵌套绑定和管道转换

2024-04-21

为了减少冗余的 XAML 标记,我尝试获取一般填充的单选按钮类型选择控件,即我使用ItemsControl与枚举为ItemsSource并创建一个 DataTemplate,通过检查项目的枚举值是否与当前设置相同来显示选择了哪个项目。

仅使用简单的转换器或 DataTrigger 无法完成此操作,因为需要两个绑定,因此我创建了一个通用的MutliValueConverter检查是否相等:

<CheckBox.Visibility>
    <MultiBinding Converter="{StaticResource EqualityComparisonConv}">
        <Binding Path="Key"/>
        <Binding Path="DisplayMode_Current" Source="{x:Static local:App.Settings}"/>
    </MultiBinding>
</CheckBox.Visibility>
public class EqualityComparisonConverter : IMultiValueConverter
{
    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values.Length < 2) throw new Exception("At least two inputs are needed for comparison");
        bool output = (bool)values.Skip(1).Aggregate(values[0], (x1, x2) => { return x1.Equals(x2); });
        return output;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    #endregion
}

这里明显的问题是转换器返回一个布尔值,我需要将其转换为Visibility first.

仅使用转换器将 MultiBinding 包装在另一个绑定中是行不通的,因为这些属性不是依赖属性(因此无法为其分配绑定)。我可以想到一些解决方法,例如将布尔值存储在某些Tag属性,所以我可以使用它作为新的绑定源,但我会对这样的东西更感兴趣:

<CheckBox.Visibility>
    <local:PipeConverter Converter="{StaticResource BooleanToVisibilityConv}">
        <MultiBinding Converter="{StaticResource EqualityComparisonConv}">
            <Binding Path="Key"/>
            <Binding Path="DisplayMode_Current" Source="{x:Static local:App.Settings}"/>
        </MultiBinding>
    </local:PipeConverter>
</CheckBox.Visibility>

当原始绑定发生更改时,此类需要更新其输出,并且需要能够将其输出值公开给Visibility财产,但我不知道如何实现。遇到的一个问题是需要依赖属性,因此继承自DependencyObject很好,但是从 Binding 类继承也有意义,因为 PipeConverter 应该绑定并且需要设置为另一个依赖属性的值。


基于这个想法(参见publicgk 的回答 https://stackoverflow.com/questions/5524885/nested-binding-and-piped-conversion/5525466#5525466, option C http://www.codeproject.com/KB/WPF/PipingValueConverters_WPF.aspx)可以创建一个转换器,其中包含一组内部按顺序使用的转换器,我编写了一个适合我的需要的劣质实现。即我可以在开始时使用 MultiValueConverter 并将输出通过管道传输到普通转换器列表中:

[ContentProperty("Converters")]
public class GroupConverter : IValueConverter, IMultiValueConverter
{
    private IMultiValueConverter _multiValueConverter;
    public IMultiValueConverter MultiValueConverter
    {
        get { return _multiValueConverter; }
        set { _multiValueConverter = value; }
    }

    private List<IValueConverter> _converters = new List<IValueConverter>();
    public List<IValueConverter> Converters
    {
        get { return _converters; }
        set { _converters = value; }
    }

    #region IValueConverter Members
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return GroupConvert(value, Converters);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return GroupConvertBack(value, Converters.ToArray().Reverse());
    }

    private static object GroupConvert(object value, IEnumerable<IValueConverter> converters)
    {
        return converters.Aggregate(value, (acc, conv) => { return conv.Convert(acc, typeof(object), null, null); });
    }

    private static object GroupConvertBack(object value, IEnumerable<IValueConverter> converters)
    {
        return converters.Aggregate(value, (acc, conv) => { return conv.ConvertBack(acc, typeof(object), null, null); });
    }
    #endregion

    #region IMultiValueConverter Members
    private InvalidOperationException _multiValueConverterUnsetException =
        new InvalidOperationException("To use the converter as a MultiValueConverter the MultiValueConverter property needs to be set.");

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (MultiValueConverter == null) throw _multiValueConverterUnsetException;
        var firstConvertedValue = MultiValueConverter.Convert(values, targetType, parameter, culture);
        return GroupConvert(firstConvertedValue, Converters);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        if (MultiValueConverter == null) throw _multiValueConverterUnsetException;
        var tailConverted = GroupConvertBack(value, Converters.ToArray().Reverse());
        return MultiValueConverter.ConvertBack(tailConverted, targetTypes, parameter, culture);
    }

    #endregion
}

(正如你所看到的,我几乎完全忽视了ConverterParameters, TargetTypes and CultureInfo参数,进一步ConvertBack方法未经测试,所以我不建议任何人实际使用它。)

XAML 用法:

<vc:GroupConverter MultiValueConverter="{StaticResource EqualityComparisonConv}">
    <StaticResource ResourceKey="BoolToVisibilityConv"/>
</vc:GroupConverter>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌套绑定和管道转换 的相关文章

随机推荐

  • 使用 NHibernate 在延迟加载场景中使用 Castle.DynamicProxy 实现 IDataErrorInfo

    我已经使用 Castle DynamicProxy IIterceptor 实现了 IDataErrorInfo 接口 我还实现了一个 NHibernate 拦截器 它使用该拦截器实例化我的实体 问题在于延迟加载的实体 这些是使用 nhib
  • 在现代 Perl 中编写异常类的最佳实践

    With Exception Class https metacpan org pod Exception Class 我可以将异常定义为类 并且一旦将它们加载到任何地方 它们就可以在任何地方使用 但是很多地方 包括 E C 本身的文档 都
  • 在 Inno Setup 中获取 MAC 地址

    我尝试使用下面的代码来获取 Inno Setup 中的 mac 地址 但出现错误 内部错误 ExtractTemporaryFile 找不到文件 ISID dll 我已经复制了ISID dll在应用程序文件夹中仍然出现上述错误 如果我遗漏了
  • ggplot 中不同宽度的堆积条形图

    我尝试构建一个具有不同宽度的堆积条形图 以便宽度表示分配的平均数量 而高度表示分配的数量 接下来 您将找到我的可重现数据 procedure c method1 method2 method3 method4 method1 method2
  • 如何将整数转换为字符串? [复制]

    这个问题在这里已经有答案了 可能的重复 如何在 Objective C 中从 int 转换为 string 示例代码 https stackoverflow com questions 1104815 how to convert from
  • 尝试从c++ linux执行命令行代码

    我尝试了以下代码 从 C 代码与命令行进行通信 include
  • 使用 Python 请求发送 SOAP 请求

    是否可以使用Python的requests http docs python requests org en master 库发送 SOAP 请求 这确实是可能的 以下是使用普通请求库调用天气 SOAP 服务的示例 import reque
  • Docker 命令无法连接到 Docker 守护进程

    我想转向 Docker 所以我刚刚开始尝试它 我已经在 VirtualBox Ubuntu 15 10 Wily Werewolf 安装上安装了 Docker 并且作为在这里建议 https blog docker com 2015 04
  • Ecma6,Object.assign 不进行深层复制[重复]

    这个问题在这里已经有答案了 dst a 1 src edf zyx right Object assign dst src src edf zyx wrong console log dst edf zyx 我期待看到 right 作为输出
  • 如何用 C 语言从串行(SPI)连接读取数据?

    我正在尝试编写一个程序 该程序将安装在 Linux MCU Raspberry Pi 上 该程序将读取从另一个 MCU 我将自己构建的自制程序 发送到它的串行数据 我研究了如何做到这一点 并认为我有 大局 但仍然缺少一些东西 其一 我需要启
  • 没有“+=”候选者产生预期的上下文结果类型“Int”[重复]

    这个问题在这里已经有答案了 我一直在更新 Swift 3 的 Swift 代码 真的很兴奋 到目前为止一切顺利 但我确实遇到了一些我似乎无法更新的代码 我知道我错过了一些非常简单的东西 但我就是看不出是什么 这是我在 Swift 2 2 中
  • 如何获取 Facebook 元的 fb:app_id

    我们的业务简介页面为http facebook com geoflakes http facebook com geoflakes 我可以从中获取它的 idhttp graph facebook com geoflakes http gra
  • 软件包“BluetoothSDK.pkg”不受信任

    我刚刚将我的操作系统重置为 10 7 我的 mac 可以运行的最新版本 并下载了 Xcode 每当我尝试安装较旧的 iOS 模拟器时 都会出现错误The package iPhoneSimulator pkg is untrusted 安装
  • 在 GUI 内的子图中添加滚动条

    如何向子图添加滚动条 我已经阅读了很多教程 但它们似乎很难理解 例如 滚动图形演示 http www mathworks com matlabcentral fileexchange 5253 scrolling figure demo 有
  • 检查物化视图是否已填充

    使用 postgres 9 5 2 python 客户端 有什么方法可以检查是否使用查询填充了物化视图 一个不会发出警告的视图未填充的视图 快速回答 SELECT relispopulated FROM pg class WHERE rel
  • 通过 SSH 隧道连接到 gitosis 服务器

    我的 MacBook 上有一个 SSH 隧道设置 就像这样 ssh o ServerAliveInterval 3 N L 22222 gitosis server 22 email protected cdn cgi l email pr
  • 在自己的处理程序中捕获信号

    include
  • Python 3.x 中长整型中的 L 后缀

    在Python 2 x中有一个L长整型后的后缀 由于 Python 3 将所有整数视为长整数 因此这一点已被删除 从Python 3 0 的新增功能 https docs python org 3 0 whatsnew 3 0 html i
  • 动态行跨度php while循环

    i have two tables one item table and customer table 在表中 您可以看到第二个项目 ID 1002 有两个条目 我想将 colspan 添加到该项目的第 1 列和第 3 列 table tr
  • 嵌套绑定和管道转换

    为了减少冗余的 XAML 标记 我尝试获取一般填充的单选按钮类型选择控件 即我使用ItemsControl与枚举为ItemsSource并创建一个 DataTemplate 通过检查项目的枚举值是否与当前设置相同来显示选择了哪个项目 仅使用