When I try to bind a valueconverter from a defined enum Status to brush, I get an error in my XAML designer:
'OKStatus' resource not found.
The application works fine runtime, but I'm not able to see my GUI in the designer. My resources are defined in the color.xaml file, which is read at run time. All code is within the same namespace
My XAML:
xmlns:config="clr-namespace: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>
and
Status
My converter:
[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;
}
}
In this code the frameElem wont have any knowledge of the resources I have defined I guess, so I need a way to get access to my resources during design. Is this possible?
As I have learned by TechNet Wiki, there is necessary to use MultiValue Converter and MultiValueBinding to get correct registred converter and correct FrameworkElement by the UserControl.
XAML Example:
<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>
Then the converter declaration can looks :
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)
{
.....
}
}
The detail explanation is: https://social.technet.microsoft.com/wiki/contents/articles/12423.wpfhowto-pass-and-use-a-control-in-it-s-own-valueconverter-for-convertconvertback.aspx
Yes, it is possible, and your guess is correct. Resource finding starts with the logical tree, and creating a new FrameworkElement()
doesn't satisfy this. It's completely disconnected.
What you can do (and what you may have to do if N8's suggestion doesn't work), is to hand your converter a reference to the UserControl
as the FrameworkElement
to call FindResource()
on.
The reason N8's suggestion probably won't work is that Application.Current.FindResource()
probably starts at application-level resources and then goes to system resources, but the resources you're after are in the UserControl
's resources. If they were placed in App.xaml's resources, it would work. However, I think Application.Current
may be null
at design-time.
The easiest way I can think of to do this is in your UserControl
's constructor:
public MyUserControl(){
var boolconv = new BoolConverter();
boolconv.FrameworkElement = this;
this.Resources.Add( "BoolConverter", boolconv );
InitializeComponent();
}
I'm pretty sure it goes before InitializeComponent()
, rather than after.
Doing this in XAML would be more complicated, as you probably have to add a DependencyProperty
to your converter so that you could bind the UserControl
to it. I think that would be going overboard.
Another way is to put TrueBrush
and FalseBrush
properties on your converter and assign them in XAML, which is what I tend to do so that my converters are vague and general-use. (NB: Names are slightly different.)
<config:BoolToBrushConverter x:Key="Bool2Brush"
TrueBrush="{StaticResource OKStatusBrush}"
FalseBrush="{StaticResource ErrorStatusBrush}" />
I think the issue is that you are trying to find the resource out of a framework element not in the visual tree. Could you try the following instead?
Application.Current.FindResource("OKStatus") as Brush;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With