使用资源作为转换会导致绑定转换器

时间:2011-06-01 13:21:09

标签: wpf staticresource valueconverter

当我尝试将valueconverter从定义的枚举状态绑定到画笔时,我在XAML设计器中出错:

找不到'OKStatus'资源。

应用程序运行良好,但我无法在设计器中看到我的GUI。 我的资源在color.xaml文件中定义,该文件在运行时读取。 所有代码都在同一名称空间中

我的XAML:

的xmlns:配置= “CLR-名称空间:App.MyNamespace”

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="c:\Skins\Colors.xaml" />
            <ResourceDictionary Source="c:\Skins\Common.xaml" />                
        </ResourceDictionary.MergedDictionaries>
        <config:StatusConverter x:Key="StateConverter" />
        <config:BoolConverter x:Key="BoolConverter" />
        <config:BooleanConverter x:Key="BooleanConverter" />
    </ResourceDictionary>
</UserControl.Resources>

状态

我的转换器:

[ValueConversion(typeof(bool), typeof(Brush))]
public class BoolConverter : IValueConverter
{
    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        bool state = (bool)value;

        FrameworkElement FrameElem = new FrameworkElement();

        if (state == true)
            return (FrameElem.FindResource("OKStatus") as Brush);
        else
            return (FrameElem.FindResource("ErrorStatus") as Brush);
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        return null;
    }
}

在这段代码中,frameElem不会对我所定义的资源有任何了解,所以我需要一种方法来在设计过程中访问我的资源。 这可能吗?

5 个答案:

答案 0 :(得分:14)

是的,这是可能的,你的猜测是正确的。资源查找从逻辑树开始,创建新的FrameworkElement()不满足此要求。它完全断开了。

如果N8的建议不起作用,您可以做什么(以及您可能需要做的事情),就是将转换器作为UserControl的引用,作为FrameworkElement来调用{{1在...上。

N8的建议可能不起作用的原因是FindResource()可能从应用程序级资源开始然后转到系统资源,但是你所追求的资源在Application.Current.FindResource()中资源。如果将它们放在App.xaml的资源中,那就可以了。但是,我认为UserControl在设计时可能是Application.Current

我能想到的最简单的方法是在null的构造函数中:

UserControl

我很确定它会在public MyUserControl(){ var boolconv = new BoolConverter(); boolconv.FrameworkElement = this; this.Resources.Add( "BoolConverter", boolconv ); InitializeComponent(); } 之前,而不是之后。

在XAML中执行此操作会更复杂,因为您可能需要在转换器中添加InitializeComponent(),以便将DependencyProperty绑定到它。我认为那将会过分。

另一种方法是在转换器上放置UserControlTrueBrush属性并在XAML中分配它们,这是我倾向于这样做,以便我的转换器模糊和通用。 (注意:名称略有不同。)

FalseBrush

答案 1 :(得分:6)

我认为问题在于您试图从不在可视化树中的框架元素中找到资源。您可以尝试以下方式吗?

Application.Current.FindResource("OKStatus") as Brush;

答案 2 :(得分:1)

正如我在TechNet Wiki上所学到的,有必要使用MultiValue Converter和MultiValueBinding来获取正确的注册转换器并通过UserControl更正FrameworkElement。

XAML示例:

<TextBlock x:Name="tb1" Margin="20">
 <TextBlock.Text>
  <MultiBinding Converter="{StaticResource MyConverter}">
   <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}"/>
   <Binding Path="MyValue"/>
  </MultiBinding>
</TextBlock.Text>
</TextBlock>

然后转换器声明可以看起来:

public class MyConverter : IMultiValueConverter
{
     FrameworkElement myControl;
     object theValue;

     public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
     {
        myControl = values[0] as FrameworkElement;
        theValue = values[1];

         return myControl.FindResource(">>resource u need<<"); 
      }

       public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
  {
  .....
  }
}

详细说明如下: https://social.technet.microsoft.com/wiki/contents/articles/12423.wpfhowto-pass-and-use-a-control-in-it-s-own-valueconverter-for-convertconvertback.aspx

答案 3 :(得分:0)

我也遇到过这个问题。我认为调用Application.Current是从IValueConverter获取资源的最佳方式,因为它们不是在每个窗口,页面或控件级别上定义的。如上所述,这将要求资源至少是应用程序级别。

但是,由于设计器中Application.Current引用设置为null,因此此方法将始终破坏设计器。您似乎已经完成了为设计人员显示的内容,同时您已经让正在运行的应用程序访问转换器中的资源。

对于有这个问题的所有人,你不需要实施lewi实施的Kludge;这只是在您希望加载设计器表面时。它在运行时不会影响您的应用程序,因为Application.Current调用有事可做。

答案 4 :(得分:-1)

实际上我最终做的(现在)是从FindResource更改为TryFindResource,并将语句放在try / catch块中。 到目前为止,这似乎有效。

try
{
    if (state == true)
       return (FrameElem.TryFindResource("OKStatus") as Brush);
    else
       return (FrameElem.TryFindResource("ErrorStatus") as Brush);
}

catch (ResourceReferenceKeyNotFoundException)
{
   return new SolidColorBrush(Colors.LightGray);
}