当我尝试将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不会对我所定义的资源有任何了解,所以我需要一种方法来在设计过程中访问我的资源。 这可能吗?
答案 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
绑定到它。我认为那将会过分。
另一种方法是在转换器上放置UserControl
和TrueBrush
属性并在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)
{
.....
}
}
答案 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);
}