2011-06-01 54 views
9

当我尝试将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> 

状态

My conver之三:

[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不会有我定义我猜资源的任何知识,所以我需要一种方式来获得设计时访问我的资源。 这可能吗?

回答

-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); 
} 
+0

我个人与Joel的解决方案一起上面,因为它似乎更少计算密集型。 TryFindResource会在我的应用程序中花费我不得不修改巨大数据网格中的项目颜色。 – Eternal21 2014-03-04 20:56:18

6

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

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

让我知道如果我是关闭基地。 – 2011-06-01 13:33:30

+1

如果资源位于应用程序级字典或系统资源中,这肯定会起作用。 – 2011-06-01 15:55:06

11

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

你能做什么(什么你可能必须做的,如果N8的建议不工作),是你的手转换器参考UserControlFrameworkElement调用FindResource()上。

N8的建议可能不会起作用的原因是Application.Current.FindResource()可能从应用程序级资源开始,然后转到系统资源,但是您之后的资源位于UserControl的资源中。如果他们被放在App.xaml的资源中,它就会工作。但是,我认为在设计时Application.Current可能是null

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

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

我敢肯定它InitializeComponent()先,而不是之后。

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

另一种方法是把你的转换器TrueBrushFalseBrush性能和XAML,这是我倾向于这样做,我的转换是含糊和笼统使用它们分配。 (注意:名称略有不同。)

<config:BoolToBrushConverter x:Key="Bool2Brush" 
         TrueBrush="{StaticResource OKStatusBrush}" 
         FalseBrush="{StaticResource ErrorStatusBrush}" /> 
+1

谢谢乔尔,你的解决方案听起来很干净。我对WPF世界很新。 – 2011-06-01 14:26:53

+0

这(使用属性)绝对是一个更好的解决方案。 – CJBrew 2016-03-08 12:46:43

0

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

但是,由于Application.Current引用在设计器中设置为null,所以此方法将始终打破设计器。你看起来已经做了什么给设计师显示一些东西,而你已经给了你正在运行的应用程序访问转换器中的资源。

对于你们所有人在这个问题上,你不需要执行lewi实施的Kludge;这只有在你想要加载设计师表面的情况下。它不会影响您的应用程序,因为Application.Current调用需要执行。

0

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