Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 绑定到资源密钥,WPF_C#_Wpf_Binding_Dynamicresource - Fatal编程技术网

C# 绑定到资源密钥,WPF

C# 绑定到资源密钥,WPF,c#,wpf,binding,dynamicresource,C#,Wpf,Binding,Dynamicresource,我有一个带有一些图像的ResourceDictionary: <BitmapImage UriSource="..\Images\Bright\folder-bright.png" x:Key="FolderItemImage" /> 现在,当显示项目时: 文本块显示FolderItemImage 显示第一幅图像 第二个图像未显示 整个想法是将项目图像设置为存储在资源中的图像,但不幸的是,上面介绍的技术无法工作

我有一个带有一些图像的ResourceDictionary:

<BitmapImage UriSource="..\Images\Bright\folder-bright.png"
             x:Key="FolderItemImage" />
现在,当显示项目时:

  • 文本块显示
    FolderItemImage
  • 显示第一幅图像
  • 第二个图像未显示

整个想法是将项目图像设置为存储在资源中的图像,但不幸的是,上面介绍的技术无法工作,现在我知道了原因:

<Image x:Name="iIcon3" Width="16" Height="16" Margin="0, 1, 3, 1" >
    <Image.Source>
        <DynamicResource ResourceKey="{Binding ImageResourceKey}" />
    </Image.Source>
</Image>

结果:

PresentationFramework.dll中发生类型为“System.Windows.Markup.XamlParseException”的未处理异常

其他信息:无法在“DynamicResourceExtension”类型的“ResourceKey”属性上设置“Binding”。只能对DependencyObject的DependencyProperty设置“绑定”


所以我必须重新表述我的问题:如何将存储在模型中的一些数据(可能是资源密钥)转换为动态资源?它必须是一个动态资源,因为我确信它在运行时可能会发生变化。

我认为不可能以您尝试的方式使用动态字符串值作为字典的键

您需要制作一个
转换器
,将
字符串
转换为
图像源
,或者根据
图像资源键
使用
数据触发器
选择

使用转换器:

在资源方面:

<local:StringToResource x:Key="StringToResource" />

未测试

无法直接执行。但还有另一种方法涉及附加属性:

public static class ImageHelper {

    private static void SourceResourceKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {

        var element = d as Image;
        if (element != null) {

            element.SetResourceReference(Image.SourceProperty, e.NewValue);
        }
    }

    public static readonly DependencyProperty SourceResourceKeyProperty = DependencyProperty.RegisterAttached("SourceResourceKey",
        typeof(object),
        typeof(ImageHelper),
        new PropertyMetadata(String.Empty, SourceResourceKeyChanged));

    public static void SetSourceResourceKey(Image element, object value) {

        element.SetValue(SourceResourceKeyProperty, value);
    }

    public static object GetSourceResourceKey(Image element) {

        return element.GetValue(SourceResourceKeyProperty);
    }
}
然后:

<Image local:ImageHelper.SourceResourceKey="{Binding SomeValue}" />

我编写了以下标记扩展,以允许在一般情况下绑定到resourceKey

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace Mersoft.Mvvm.MarkupExtensions
{

    public class ResourceBinding : MarkupExtension
    {
        #region Helper properties

        public static object GetResourceBindingKeyHelper(DependencyObject obj)
        {
            return (object)obj.GetValue(ResourceBindingKeyHelperProperty);
        }

        public static void SetResourceBindingKeyHelper(DependencyObject obj, object value)
        {
            obj.SetValue(ResourceBindingKeyHelperProperty, value);
        }

        // Using a DependencyProperty as the backing store for ResourceBindingKeyHelper.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ResourceBindingKeyHelperProperty =
            DependencyProperty.RegisterAttached("ResourceBindingKeyHelper", typeof(object), typeof(ResourceBinding), new PropertyMetadata(null, ResourceKeyChanged));

        static void ResourceKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = d as FrameworkElement;
            var newVal = e.NewValue as Tuple<object, DependencyProperty>;

            if (target == null || newVal == null)
                return;

            var dp = newVal.Item2;

            if (newVal.Item1 == null)
            {
                target.SetValue(dp, dp.GetMetadata(target).DefaultValue);
                return;
            }

            target.SetResourceReference(dp, newVal.Item1);

        }

        #endregion

        public ResourceBinding()
        {

        }

        public ResourceBinding(string path)
        {
            this.Path = new PropertyPath(path);
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var provideValueTargetService = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
            if (provideValueTargetService == null)
                return null;

            if (provideValueTargetService.TargetObject != null &&
                provideValueTargetService.TargetObject.GetType().FullName == "System.Windows.SharedDp")
                return this;


            var targetObject = provideValueTargetService.TargetObject as FrameworkElement;
            var targetProperty = provideValueTargetService.TargetProperty as DependencyProperty;
            if (targetObject == null || targetProperty == null)
                return null;



            var binding = new Binding();

            #region binding

            binding.Path = this.Path;
            binding.XPath = this.XPath;
            binding.Mode = this.Mode;
            binding.UpdateSourceTrigger = this.UpdateSourceTrigger;
            binding.Converter = this.Converter;
            binding.ConverterParameter = this.ConverterParameter;
            binding.ConverterCulture = this.ConverterCulture;

            if (this.RelativeSource != null)
                binding.RelativeSource = this.RelativeSource;

            if (this.ElementName != null)
                binding.ElementName = this.ElementName;

            if (this.Source != null)
                binding.Source = this.Source;

            binding.FallbackValue = this.FallbackValue;

            #endregion

            var multiBinding = new MultiBinding();
            multiBinding.Converter = HelperConverter.Current;
            multiBinding.ConverterParameter = targetProperty;

            multiBinding.Bindings.Add(binding);

            multiBinding.NotifyOnSourceUpdated = true;

            targetObject.SetBinding(ResourceBindingKeyHelperProperty, multiBinding);

            return null;

        }


        #region Binding Members

        /// <summary> The source path (for CLR bindings).</summary>
        public object Source
        {
            get;
            set;
        }

        /// <summary> The source path (for CLR bindings).</summary>
        public PropertyPath Path
        {
            get;
            set;
        }

        /// <summary> The XPath path (for XML bindings).</summary>
        [DefaultValue(null)]
        public string XPath
        {
            get;
            set;
        }

        /// <summary> Binding mode </summary>
        [DefaultValue(BindingMode.Default)]
        public BindingMode Mode
        {
            get;
            set;
        }

        /// <summary> Update type </summary>
        [DefaultValue(UpdateSourceTrigger.Default)]
        public UpdateSourceTrigger UpdateSourceTrigger
        {
            get;
            set;
        }

        /// <summary> The Converter to apply </summary>
        [DefaultValue(null)]
        public IValueConverter Converter
        {
            get;
            set;
        }

        /// <summary>
        /// The parameter to pass to converter.
        /// </summary>
        /// <value></value>
        [DefaultValue(null)]
        public object ConverterParameter
        {
            get;
            set;
        }

        /// <summary> Culture in which to evaluate the converter </summary>
        [DefaultValue(null)]
        [TypeConverter(typeof(System.Windows.CultureInfoIetfLanguageTagConverter))]
        public CultureInfo ConverterCulture
        {
            get;
            set;
        }

        /// <summary>
        /// Description of the object to use as the source, relative to the target element.
        /// </summary>
        [DefaultValue(null)]
        public RelativeSource RelativeSource
        {
            get;
            set;
        }

        /// <summary> Name of the element to use as the source </summary>
        [DefaultValue(null)]
        public string ElementName
        {
            get;
            set;
        }


        #endregion

        #region BindingBase Members

        /// <summary> Value to use when source cannot provide a value </summary>
        /// <remarks>
        ///     Initialized to DependencyProperty.UnsetValue; if FallbackValue is not set, BindingExpression
        ///     will return target property's default when Binding cannot get a real value.
        /// </remarks>
        public object FallbackValue
        {
            get;
            set;
        }

        #endregion



        #region Nested types

        private class HelperConverter : IMultiValueConverter
        {
            public static readonly HelperConverter Current = new HelperConverter();

            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                return Tuple.Create(values[0], (DependencyProperty)parameter);
            }
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }

        #endregion
    }
}
使用系统;
使用系统组件模型;
利用制度全球化;
使用System.Windows;
使用System.Windows.Data;
使用System.Windows.Markup;
命名空间Mersoft.Mvvm.MarkupExtensions
{
公共类ResourceBinding:MarkupExtension
{
#区域辅助属性
公共静态对象GetResourceBindingKeyHelper(DependencyObject obj)
{
返回(对象)obj.GetValue(ResourceBindingKeyHelperProperty);
}
公共静态void SetResourceBindingKeyHelper(DependencyObject对象,对象值)
{
obj.SetValue(ResourceBindingKeyHelperProperty,value);
}
//使用DependencyProperty作为ResourceBindingKeyHelper的备份存储。这将启用动画、样式、绑定等。。。
公共静态只读从属属性ResourceBindingKeyHelperProperty=
RegisterAttached(“ResourceBindingKeyHelper”、typeof(object)、typeof(ResourceBinding)、new PropertyMetadata(null,ResourceKeyChanged));
静态void ResourceKeyChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
var target=d作为框架元素;
var newVal=e.NewValue作为元组;
if(target==null | | newVal==null)
返回;
var dp=newVal.Item2;
if(newVal.Item1==null)
{
target.SetValue(dp,dp.GetMetadata(target.DefaultValue));
返回;
}
target.SetResourceReference(dp,newVal.Item1);
}
#端区
公共资源绑定()
{
}
公共资源绑定(字符串路径)
{
this.Path=新属性路径(Path);
}
公共覆盖对象ProviderValue(IServiceProvider服务提供程序)
{
var provideValueTargetService=(IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
如果(provideValueTargetService==null)
返回null;
如果(provideValueTargetService.TargetObject!=空&&
provideValueTargetService.TargetObject.GetType().FullName==“System.Windows.SharedDp”)
归还这个;
var targetObject=provideValueTargetService.targetObject作为框架元素;
var targetProperty=provideValueTargetService.targetProperty作为DependencyProperty;
if(targetObject==null | | targetProperty==null)
返回null;
var binding=新绑定();
#区域绑定
binding.Path=this.Path;
binding.XPath=this.XPath;
binding.Mode=this.Mode;
binding.UpdateSourceTrigger=this.UpdateSourceTrigger;
binding.Converter=这个.Converter;
binding.ConverterParameter=此.ConverterParameter;
binding.ConverterCulture=this.ConverterCulture;
if(this.RelativeSource!=null)
binding.RelativeSource=此.RelativeSource;
if(this.ElementName!=null)
binding.ElementName=this.ElementName;
如果(this.Source!=null)
binding.Source=this.Source;
binding.FallbackValue=this.FallbackValue;
#端区
var multiBinding=新的multiBinding();
multiBinding.Converter=HelperConverter.Current;
multiBinding.ConverterParameter=targetProperty;
multiBinding.Bindings.Add(绑定);
multiBinding.NotifyOnSourceUpdated=true;
targetObject.SetBinding(ResourceBindingKeyHelperProperty,多绑定);
返回null;
}
#区域绑定成员
///源路径(用于CLR绑定)。
公共对象源
{
得到;
设置
}
///源路径(用于CLR绑定)。
公共属性路径
{
得到;
设置
}
///XPath路径(用于XML绑定)。
[默认值(空)]
公共字符串XPath
{
得到;
设置
}
///绑定模式
[默认值(BindingMode.Default)]
公共绑定模式
{
得到;
设置
}
///更新类型
[D]
public static class ImageHelper {

    private static void SourceResourceKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {

        var element = d as Image;
        if (element != null) {

            element.SetResourceReference(Image.SourceProperty, e.NewValue);
        }
    }

    public static readonly DependencyProperty SourceResourceKeyProperty = DependencyProperty.RegisterAttached("SourceResourceKey",
        typeof(object),
        typeof(ImageHelper),
        new PropertyMetadata(String.Empty, SourceResourceKeyChanged));

    public static void SetSourceResourceKey(Image element, object value) {

        element.SetValue(SourceResourceKeyProperty, value);
    }

    public static object GetSourceResourceKey(Image element) {

        return element.GetValue(SourceResourceKeyProperty);
    }
}
<Image local:ImageHelper.SourceResourceKey="{Binding SomeValue}" />
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace Mersoft.Mvvm.MarkupExtensions
{

    public class ResourceBinding : MarkupExtension
    {
        #region Helper properties

        public static object GetResourceBindingKeyHelper(DependencyObject obj)
        {
            return (object)obj.GetValue(ResourceBindingKeyHelperProperty);
        }

        public static void SetResourceBindingKeyHelper(DependencyObject obj, object value)
        {
            obj.SetValue(ResourceBindingKeyHelperProperty, value);
        }

        // Using a DependencyProperty as the backing store for ResourceBindingKeyHelper.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ResourceBindingKeyHelperProperty =
            DependencyProperty.RegisterAttached("ResourceBindingKeyHelper", typeof(object), typeof(ResourceBinding), new PropertyMetadata(null, ResourceKeyChanged));

        static void ResourceKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = d as FrameworkElement;
            var newVal = e.NewValue as Tuple<object, DependencyProperty>;

            if (target == null || newVal == null)
                return;

            var dp = newVal.Item2;

            if (newVal.Item1 == null)
            {
                target.SetValue(dp, dp.GetMetadata(target).DefaultValue);
                return;
            }

            target.SetResourceReference(dp, newVal.Item1);

        }

        #endregion

        public ResourceBinding()
        {

        }

        public ResourceBinding(string path)
        {
            this.Path = new PropertyPath(path);
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var provideValueTargetService = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
            if (provideValueTargetService == null)
                return null;

            if (provideValueTargetService.TargetObject != null &&
                provideValueTargetService.TargetObject.GetType().FullName == "System.Windows.SharedDp")
                return this;


            var targetObject = provideValueTargetService.TargetObject as FrameworkElement;
            var targetProperty = provideValueTargetService.TargetProperty as DependencyProperty;
            if (targetObject == null || targetProperty == null)
                return null;



            var binding = new Binding();

            #region binding

            binding.Path = this.Path;
            binding.XPath = this.XPath;
            binding.Mode = this.Mode;
            binding.UpdateSourceTrigger = this.UpdateSourceTrigger;
            binding.Converter = this.Converter;
            binding.ConverterParameter = this.ConverterParameter;
            binding.ConverterCulture = this.ConverterCulture;

            if (this.RelativeSource != null)
                binding.RelativeSource = this.RelativeSource;

            if (this.ElementName != null)
                binding.ElementName = this.ElementName;

            if (this.Source != null)
                binding.Source = this.Source;

            binding.FallbackValue = this.FallbackValue;

            #endregion

            var multiBinding = new MultiBinding();
            multiBinding.Converter = HelperConverter.Current;
            multiBinding.ConverterParameter = targetProperty;

            multiBinding.Bindings.Add(binding);

            multiBinding.NotifyOnSourceUpdated = true;

            targetObject.SetBinding(ResourceBindingKeyHelperProperty, multiBinding);

            return null;

        }


        #region Binding Members

        /// <summary> The source path (for CLR bindings).</summary>
        public object Source
        {
            get;
            set;
        }

        /// <summary> The source path (for CLR bindings).</summary>
        public PropertyPath Path
        {
            get;
            set;
        }

        /// <summary> The XPath path (for XML bindings).</summary>
        [DefaultValue(null)]
        public string XPath
        {
            get;
            set;
        }

        /// <summary> Binding mode </summary>
        [DefaultValue(BindingMode.Default)]
        public BindingMode Mode
        {
            get;
            set;
        }

        /// <summary> Update type </summary>
        [DefaultValue(UpdateSourceTrigger.Default)]
        public UpdateSourceTrigger UpdateSourceTrigger
        {
            get;
            set;
        }

        /// <summary> The Converter to apply </summary>
        [DefaultValue(null)]
        public IValueConverter Converter
        {
            get;
            set;
        }

        /// <summary>
        /// The parameter to pass to converter.
        /// </summary>
        /// <value></value>
        [DefaultValue(null)]
        public object ConverterParameter
        {
            get;
            set;
        }

        /// <summary> Culture in which to evaluate the converter </summary>
        [DefaultValue(null)]
        [TypeConverter(typeof(System.Windows.CultureInfoIetfLanguageTagConverter))]
        public CultureInfo ConverterCulture
        {
            get;
            set;
        }

        /// <summary>
        /// Description of the object to use as the source, relative to the target element.
        /// </summary>
        [DefaultValue(null)]
        public RelativeSource RelativeSource
        {
            get;
            set;
        }

        /// <summary> Name of the element to use as the source </summary>
        [DefaultValue(null)]
        public string ElementName
        {
            get;
            set;
        }


        #endregion

        #region BindingBase Members

        /// <summary> Value to use when source cannot provide a value </summary>
        /// <remarks>
        ///     Initialized to DependencyProperty.UnsetValue; if FallbackValue is not set, BindingExpression
        ///     will return target property's default when Binding cannot get a real value.
        /// </remarks>
        public object FallbackValue
        {
            get;
            set;
        }

        #endregion



        #region Nested types

        private class HelperConverter : IMultiValueConverter
        {
            public static readonly HelperConverter Current = new HelperConverter();

            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                return Tuple.Create(values[0], (DependencyProperty)parameter);
            }
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }

        #endregion
    }
}
<Image Source="{local:ResourceBinding ImageResourceKey}"/>
public class DynamicResourceBinding : MarkupExtension
{
    public DynamicResourceBinding(string path)
    {
        binding = new Binding(path);
    }

    #region Binding Members

    public PropertyPath Path
    {
        get { return binding.Path; }
        set { binding.Path = value; }
    }
    public string XPath
    {
        get { return binding.XPath; }
        set { binding.XPath = value; }
    }
    [DefaultValue(BindingMode.Default)]
    public BindingMode Mode
    {
        get { return binding.Mode; }
        set { binding.Mode = value; }
    }
    [DefaultValue(UpdateSourceTrigger.Default)]
    public UpdateSourceTrigger UpdateSourceTrigger
    {
        get { return binding.UpdateSourceTrigger; }
        set { binding.UpdateSourceTrigger = value; }
    }
    public IValueConverter Converter
    {
        get { return binding.Converter; }
        set { binding.Converter = value; }
    }
    public object ConverterParameter
    {
        get { return binding.ConverterParameter; }
        set { binding.ConverterParameter = value; }
    }
    [TypeConverter(typeof(CultureInfoIetfLanguageTagConverter))]
    public CultureInfo ConverterCulture
    {
        get { return binding.ConverterCulture; }
        set { binding.ConverterCulture = value; }
    }
    public object Source
    {
        get { return binding.Source; }
        set { binding.Source = value; }
    }
    public string ElementName
    {
        get { return binding.ElementName; }
        set { binding.ElementName = value; }
    }
    public RelativeSource RelativeSource
    {
        get { return binding.RelativeSource; }
        set { binding.RelativeSource = value; }
    }
    public object FallbackValue
    {
        get { return binding.FallbackValue; }
        set { binding.FallbackValue = value; }
    }

    private readonly Binding binding;

    #endregion Binding Members

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        if (provideValueTarget != null)
        {
            var targetObject = provideValueTarget.TargetObject as FrameworkElement;
            if (targetObject != null)
            {
                var targetProperty = provideValueTarget.TargetProperty as DependencyProperty;
                if (targetProperty != null)
                {
                    targetObject.SetBinding(EnsureResourceKeyProperty(targetProperty), binding);
                }
            }
        }

        return null;
    }

    private static readonly object locker = new object();

    public static DependencyProperty EnsureResourceKeyProperty(DependencyProperty targetProperty)
    {
        DependencyProperty resourceKeyProperty;
        lock (locker)
        {
            if (!DirectMap.TryGetValue(targetProperty, out resourceKeyProperty))
            {
                resourceKeyProperty = RegisterResourceKeyProperty(targetProperty);
                DirectMap.Add(targetProperty, resourceKeyProperty);
                ReverseMap.Add(resourceKeyProperty, targetProperty);
            }
        }
        return resourceKeyProperty;
    }

    private static DependencyProperty RegisterResourceKeyProperty(DependencyProperty targetProperty)
    {
        return DependencyProperty.RegisterAttached(targetProperty.Name + "_ResourceKey", typeof(object), typeof(DynamicResourceBinding),
            new PropertyMetadata(ResourceKeyChanged));
    }

    private static void ResourceKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var fe = d as FrameworkElement;
        if (fe != null)
        {
            lock (locker)
            {
                DependencyProperty targetProperty;
                if (ReverseMap.TryGetValue(e.Property, out targetProperty))
                {
                    fe.SetResourceReference(targetProperty, e.NewValue);
                }
            }
        }
    }

    private static readonly Dictionary<DependencyProperty, DependencyProperty> DirectMap = new Dictionary<DependencyProperty, DependencyProperty>();
    private static readonly Dictionary<DependencyProperty, DependencyProperty> ReverseMap = new Dictionary<DependencyProperty, DependencyProperty>();
}