13

当我尝试将值转换器从定义的枚举状态绑定到刷子时,我的 XAML 设计器中出现错误:

未找到“OKStatus”资源。

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

我的 XAML:

xmlns:config="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 不会知道我定义的资源,所以我需要一种方法来在设计期间访问我的资源。这可能吗?

4

5 回答 5

17

是的,这是可能的,而且您的猜测是正确的。资源查找从逻辑树开始,创建一个新的FrameworkElement()并不能满足这一点。它完全断开了。

您可以做的(以及如果 N8 的建议不起作用,您可能需要做的事情)是将您的转换器UserControl作为FrameworkElement调用的参考FindResource()

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

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

public MyUserControl(){
    var boolconv = new BoolConverter(); 
    boolconv.FrameworkElement = this;
    this.Resources.Add( "BoolConverter", boolconv );
    InitializeComponent();
}

我很确定它在之前InitializeComponent(),而不是之后。

在 XAML 中执行此操作会更加复杂,因为您可能必须将 a 添加DependencyProperty到您的转换器,以便您可以将其绑定UserControl到它。我认为那会过火。

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

<config:BoolToBrushConverter x:Key="Bool2Brush"
                      TrueBrush="{StaticResource OKStatusBrush}"
                      FalseBrush="{StaticResource ErrorStatusBrush}" />
于 2011-06-01T13:40:16.970 回答
6

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

Application.Current.FindResource("OKStatus") as Brush;
于 2011-06-01T13:33:20.020 回答
3

正如我从 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

于 2017-08-27T16:46:06.090 回答
0

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

但是,由于在Application.Current设计器中将引用设置为 null,因此这种方法总是会破坏设计器。您所做的似乎是为设计人员提供了一些显示内容,同时您已让正在运行的应用程序访问转换器中的资源。

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

于 2012-06-04T19:18:28.820 回答
-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);
}
于 2011-06-08T10:48:27.187 回答