Telerik Tile Background binding - wpf

I'm trying to bind the background of a Tile in a RadTileList, Tiles are created from a collection on the Itemsource of the RadTileList, so far I've tried changing the background on the border container in the Datatemplate, but it seems that the Tile background property is wining over that.
In the code above , I've tried to set the ItemContainerStyle and set the binding for the background, but nothing changes, I hope someone could help me.
Note: The color of the background is a string var so im using a converter, wich I tested independently
<telerik:RadTileList ItemsSource="{Binding Modulo.Modulos_Detail}" TileReorderMode="None"
ScrollViewer.HorizontalScrollBarVisibility="Visible">
<telerik:RadTileList.ItemContainerStyle>
<Style >
<Setter Property="telerik:Tile.TileType" Value="Quadruple" />
<Setter Property="telerik:Tile.Background" Value="{Binding .Color, Converter={StaticResource strHexColorConverter}}" />
</Style>
</telerik:RadTileList.ItemContainerStyle>
<telerik:RadTileList.ItemTemplate>
<DataTemplate>
<Border >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image Grid.Row="0"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Source="{Binding .Imagenes.Imagen}" Stretch="Uniform"></Image>
<TextBlock Grid.Row="1" Padding="5"
Text="{Binding Descripcion}" FontSize="20" TextWrapping="Wrap"
VerticalAlignment="Bottom"/>
<!--<Image Source="{Binding .LockViewImage, Converter={StaticResource imgBitmapImageConverter}}" />-->
</Grid>
</Border>
</DataTemplate>
</telerik:RadTileList.ItemTemplate>

Create a seperate style with the Tile as target type. Then you only need to set the Background property. Optionally you could give the style a name and set it explicitly on the RadTileList.
<UserControl.Resources>
<ResourceDictionary>
<Style TargetType="telerik:Tile" BasedOn="{StaticResource TileStyle}">
<Setter Property="Background" Value="{StaticResource OmegaMainColorBrush}" />
</Style>
</ResourceDictionary>
</UserControl.Resources>

In my opinion you can use a Boolean Attached property in the telerik:Tile control style. If that property is True then you create the binding in code behind. The only one thing you should care about is that the Content of the Tile will hold the the object that the .Color is defined there.
Here is the code.
Style (put this into the Resource part)
<Style TargetType="telerik:Tile" BasedOn="{StaticResource {x:Type telerik:Tile}}">
<Setter Property="flowConfiguration:TileAttachedProperties.IsTyleTypeBound" Value="True"/>
</Setter>
The attached property code(with converters)
public class TileAttachedProperties
{
public static readonly DependencyProperty IsTyleTypeBoundProperty = DependencyProperty.RegisterAttached(
"IsTyleTypeBound",
typeof (bool),
typeof (TileAttachedProperties),
new PropertyMetadata(default(bool), IsTyleBoundPropertyChangedCallback));
private static void IsTyleBoundPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var tile = sender as Tile;
var isBound = (bool) args.NewValue;
if(tile == null || isBound == false) return;
tile.Loaded += TileOnLoaded;
}
private static void TileOnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
var tile = sender as Tile;
if (tile == null) return;
tile.Loaded -= TileOnLoaded;
var tileContent = tile.Content;
if (tileContent == null || tileContent is ItemTypeWrapper == false) return;
//here we create binding to define if the type of the Tile(single or double)
var tileTypeBinding = new Binding("IsDouble");
tileTypeBinding.Source = tileContent;
tileTypeBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
tileTypeBinding.Converter = new Bool2TileTypeConverter();
tile.SetBinding(Tile.TileTypeProperty, tileTypeBinding);
//here we create binding to define the background of the tile
var tileBackgroundBinding = new Binding("IsDouble");
tileBackgroundBinding.Source = tileContent;
tileBackgroundBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
tileBackgroundBinding.Converter = new Bool2BackgroundConverter();
tile.SetBinding(Tile.BackgroundProperty, tileBackgroundBinding);
}
public static void SetIsTyleTypeBound(DependencyObject element, bool value)
{
element.SetValue(IsTyleTypeBoundProperty, value);
}
public static bool GetIsTyleTypeBound(DependencyObject element)
{
return (bool) element.GetValue(IsTyleTypeBoundProperty);
}
}
internal class Bool2BackgroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var isDouble = (bool)value;
return isDouble ? new SolidColorBrush(Color.FromArgb(255, 255, 0, 255)) : new SolidColorBrush(Color.FromArgb(255,0, 255, 255));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
internal class Bool2TileTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var isDouble = (bool) value;
return isDouble ? TileType.Double : TileType.Single;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
How it looks like:
Regards,

Related

wpf combobox multibinding could not get combobox items (programmatically added or bind to database) of relative source combobox in first step

I want to disable some items of combobox by specific conditions. For this issue, I used multibinding.
If I described all items of combobox in xaml, there is no problem. But I want to populate combobox items programmatically. So in this case , I could not get items, returns null, and throw me out of the program in the first step.
my xaml codes are like that:
<Window.Resources>
<local:TekerDisabler x:Key="tekerDisabler"/>
</Window.Resources>
<Grid>
<ComboBox x:Name="cbx" HorizontalAlignment="Left" Margin="41,125,0,0" VerticalAlignment="Top" Width="227">
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnabled">
<Setter.Value>
<MultiBinding Converter="{StaticResource tekerDisabler}">
<Binding ElementName="txt1" Path="Text"/>
<Binding ElementName="txt2" Path="Text"/>
<Binding ElementName="txt3" Path="Text"/>
<Binding RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
<TextBox x:Name="txt1" HorizontalAlignment="Left" Height="23" Margin="41,38,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="txt2" HorizontalAlignment="Left" Height="23" Margin="207,38,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="211" TextChanged="txt2_TextChanged"/>
<TextBox x:Name="txt3" HorizontalAlignment="Left" Height="24" Margin="478,37,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="196"/>
</Grid>
and my c# codes are like that:
namespace App1.Pencereler
{
public partial class deneme : Window
{
public deneme()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
cbx.Items.Add("0");
cbx.Items.Add("1");
cbx.Items.Add("2");
cbx.Items.Add("3");
}
private void txt2_TextChanged(object sender, TextChangedEventArgs e)
{
cbx.SelectedIndex = 1;
}
}
class TekerDisabler : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool enable = true;
var itemler = values[3] as ComboBoxItem;
if (itemler == null || values[0].ToString() == null || values[1].ToString() == null || values[2].ToString() == null)
{ enable = true; }
else
{
switch (values[0].ToString())
{
case "a":
switch (values[1].ToString())
{
case "b":
switch (values[2].ToString())
{
case "c":
switch (itemler.Content.ToString())
{
case "0":
case "2":
enable = false;
break;
default:
enable = true;
break;
}
break;
default:
enable = true;
break;
}
break;
default:
enable = true;
break;
}
break;
default:
enable = true;
break;
}
}
return enable;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
For Example, in the first step, I write txt1:a, txt2:b, txt3:d and so all items' display enabled, and then I write txt1:a, txt2:b, txt3:c and contents of combobox (0,2) disabled, there is no problem. But when running program, in the first step I write txt1:a, txt2:b, txt3:c when drop down combobox, program trow me out.
How to overcome this problem?
Error Message and details are like that:
And Error details are like that:
System.NullReferenceException
HResult=0x80004003
İleti=Nesne başvurusu bir nesnenin örneğine ayarlanmadı.
Kaynak=App1
StackTrace:
konum App1.Pencereler.TekerDisabler.Convert(Object[] values, Type targetType, Object parameter, CultureInfo culture) D:\C Sharp\WPF\App1\App1\Pencereler\deneme.xaml.cs içinde: 60. satır
konum System.Windows.Data.MultiBindingExpression.TransferValue()
konum System.Windows.Data.MultiBindingExpression.Transfer()
konum System.Windows.Data.MultiBindingExpression.UpdateTarget(Boolean includeInnerBindings)
konum System.Windows.Data.MultiBindingExpression.AttachToContext(Boolean lastChance)
konum System.Windows.Data.MultiBindingExpression.AttachOverride(DependencyObject d, DependencyProperty dp)
konum System.Windows.Data.BindingExpressionBase.OnAttach(DependencyObject d, DependencyProperty dp)
It would be interesting to know what exact error you get.
I assume the ComboBoxItem.Content returns null. The item containers are rendered (generated) after the ComboBox is opened. Only the data items exist at this moment. So opening the drop down the first time all item containers are null and about to be rendered.
Anyway, the following simplified version of your code will very likely fix your problem:
TekerDisabler.cs
public class TekerDisabler : IMultiValueConverter
{
#region Implementation of IMultiValueConverter
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var currentItem = values[0] as string;
var predicate = "abc";
string input = string.Concat(values.Skip(1).Cast<string>());
return !(input.Equals(predicate, StringComparison.Ordinal)
&& (currentItem.Equals("0", StringComparison.Ordinal)
|| currentItem.Equals("2", StringComparison.Ordinal)));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
throw new NotSupportedException();
#endregion
}
TekerDisabler.cs - Alternative version
public class TekerDisabler : IMultiValueConverter
{
#region Implementation of IMultiValueConverter
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var currentItem = values[0] as string;
var predicate = "abc";
string input = string.Concat(values.Skip(1).Cast<string>());
return !(values[1].Equals("a", StringComparison.Ordinal)
&& values[2].Equals("b", StringComparison.Ordinal)
&& values[3].Equals("c", StringComparison.Ordinal)
&& (currentItem.Equals("0", StringComparison.Ordinal)
|| currentItem.Equals("2", StringComparison.Ordinal)));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
throw new NotSupportedException();
#endregion
}
MainWindow.xamlk.cs
partial class MainWIndow : Window
{
public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
"Items",
typeof(ObservableCollection<string>),
typeof(MainWindow),
new PropertyMetadata(default(ObservableCollection<string>)));
public ObservableCollection<string> Items
{
get => (ObservableCollection<string>) GetValue(MainWindow.ResultsProperty);
set => SetValue(MainWindow.ResultsProperty, value);
}
}
MainWindow.xaml
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=main:MainWindow}, Path=Items}">
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnabled">
<Setter.Value>
<MultiBinding Converter="{StaticResource CellForegroundMultiValueConverter}">
<Binding />
<Binding ElementName="TextBox1" Path="Text" />
<Binding ElementName="TextBox2" Path="Text" />
<Binding ElementName="TextBox3" Path="Text" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
<TextBox x:Name="TextBox1" />
<TextBox x:Name="TextBox2" />
<TextBox x:Name="TextBox3" />
I accomlished to overcome my problem by adding
cbx.IsDropDownOpen = true;
cbx.IsDropDownOpen = false;
after
cbx.Items.Add("0");
cbx.Items.Add("1");
cbx.Items.Add("2");
cbx.Items.Add("3");
in 'Window_Loaded' event.

How can I set a Static/Dynamic resource from a binding value?

I want to add dynamic items with a datatemplate that contains a TextBlock control, but the text of the TextBlock control will be selected from a XAML ResourceDictionary. The staticresource name will be obtained based on the result of the binding value.
How can I do that?
I'm trying something like this, but doesn't works.
<DataTemplate x:Key="languageItemTemplate">
<ContentControl>
<StackPanel>
<TextBlock Text="{StaticResource {Binding ResourceName}}"></TextBlock>
<TextBlock Text="{DynamicResource {Binding ResourceName}}"></TextBlock>
</StackPanel>
</ContentControl>
</DataTemplate>
UPDATE
Thanks to Tobias, the fist option of his answer works. But I need to instance the converter first to get it work. Which one is the best idea to do that?
In the application_startup method and use it for all the application or in the Window.Resources of the window I use the converter?
Maybe a merge of both and do that on the Application.Resources?
thanks for your answer.
private void Application_Startup(object sender, StartupEventArgs e)
{
LoadConverters();
}
private void LoadConverters()
{
foreach (var t in System.Reflection.Assembly.GetExecutingAssembly().GetTypes())
{
if (t.GetInterfaces().Any(i => i.Name == "IValueConverter"))
{
Resources.Add(t.Name, Activator.CreateInstance(t));
}
}
}
OR
<local:BindingResourceConverter x:Key="ResourceConverter"/>
<DataTemplate x:Key="languageItemTemplate">
<ContentControl>
<StackPanel>
<TextBlock Text="{Binding Name, Converter={StaticResource ResourceConverter }}" />
</StackPanel>
</ContentControl>
</DataTemplate>
If the resource is an application level resource you could simply use a converter to convert from the resource name to the actual object like this:
public class BindingResourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string resourceKey = value as string;
if (!String.IsNullOrEmpty(resourceKey))
{
var resource = Application.Current.FindResource(resourceKey);
if (resource != null)
{
return resource;
}
}
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And use it like this:
<TextBlock Text="{Binding ResourceKey, Converter={StaticResource ResourceConverter}}" />
If the resource is in a local scope, we need a reference to the control to search its resources. You can get the resource name and the control by using an attached property:
public class TextBlockHelper
{
public static readonly DependencyProperty TextResourceKeyProperty =
DependencyProperty.RegisterAttached("TextResourceKey", typeof(string),
typeof(TextBlockHelper), new PropertyMetadata(String.Empty, OnTextResourceKeyChanged));
public static string GetTextResourceKey(DependencyObject obj)
{
return (string)obj.GetValue(TextResourceKeyProperty);
}
public static void SetTextResourceKey(DependencyObject obj, string value)
{
obj.SetValue(TextResourceKeyProperty, value);
}
private static void OnTextResourceKeyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
string resourceKey = e.NewValue as string;
if(d is TextBlock tb)
{
var r = tb.TryFindResource(resourceKey);
if (r != null)
{
tb.Text = r.ToString();
}
}
}
}
And you can use it like this:
<Grid>
<Grid.Resources>
<sys:String x:Key="SomeLocalResource">LocalResource</sys:String>
</Grid.Resources>
<TextBlock h:TextBlockHelper.TextResourceKey="{Binding ResourceKey}" />
</Grid>

Set maximum scale of ViewBox

Is it somehow possible to set a maximum scale of the content in a ViewBox? If I have this code for instance, I want to ensure that the text is not scaled more than 200%
<Grid>
<Viewbox>
<TextBox Text="Hello world" />
</Viewbox>
</Grid>
For future readers, I've written an even more elegant approach based on user2250152's answer that uses an attached property:
public static class ViewboxExtensions
{
public static readonly DependencyProperty MaxZoomFactorProperty =
DependencyProperty.Register("MaxZoomFactor", typeof(double), typeof(ViewboxExtensions), new PropertyMetadata(1.0, OnMaxZoomFactorChanged));
private static void OnMaxZoomFactorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var viewbox = d as Viewbox;
if (viewbox == null)
return;
viewbox.Loaded += OnLoaded;
}
private static void OnLoaded(object sender, RoutedEventArgs e)
{
var viewbox = sender as Viewbox;
var child = viewbox?.Child as FrameworkElement;
if (child == null)
return;
child.SizeChanged += (o, args) => CalculateMaxSize(viewbox);
CalculateMaxSize(viewbox);
}
private static void CalculateMaxSize(Viewbox viewbox)
{
var child = viewbox.Child as FrameworkElement;
if (child == null)
return;
viewbox.MaxWidth = child.ActualWidth * GetMaxZoomFactor(viewbox);
viewbox.MaxHeight = child.ActualHeight * GetMaxZoomFactor(viewbox);
}
public static void SetMaxZoomFactor(DependencyObject d, double value)
{
d.SetValue(MaxZoomFactorProperty, value);
}
public static double GetMaxZoomFactor(DependencyObject d)
{
return (double)d.GetValue(MaxZoomFactorProperty);
}
}
The attached property can be added to a viewbox like this:
<Viewbox extensions:ViewboxExtensions.MaxZoomFactor="2.0">...</Viewbox>
You need to set MaxWidth and MaxHeight on ViewBox:
<Grid>
<Viewbox x:Name="MyViewBox">
<TextBox x:Name="MyTextBox" Text="Hello world" />
</Viewbox>
</Grid>
and in code behind:
MyViewBox.MaxWidth = MyTextBox.ActualWidth * 2d;
MyViewBox.MaxHeight = MyTextBox.ActualHeight * 2d;
Or maybe better solution with converter:
public class ViewBoxMaxWidthOrHeightConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double textBoxWidthOrHeight = (double) value;
return textBoxWidthOrHeight*2d;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
and XAML:
<local:ViewBoxMaxWidthOrHeightConverter x:Key="ViewBoxMaxWidthOrHeightConverter"/>
<Grid>
<Viewbox x:Name="MyViewBox"
MaxWidth="{Binding ElementName=MyTextBox, Path=ActualWidth, Converter={StaticResource ViewBoxMaxWidthOrHeightConverter}, Mode=OneWay}"
MaxHeight="{Binding ElementName=MyTextBox, Path=ActualHeight, Converter={StaticResource ViewBoxMaxWidthOrHeightConverter}, Mode=OneWay}">
<TextBox x:Name="MyTextBox" Text="Hello world" />
</Viewbox>
</Grid>

How can i bind a border visibility to the visibility of containing children objects

I have this kind of code below, how can I bind the visibility of the Border to the visibility of all the labels?
Of course the number of rows and labels is not fixed.
<Border BorderBrush=Black
BorderThickness="1,1,1,1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label DataContext="{Binding MyObject[1]}"
Content="{Binding MyText}"
Visibility="{Binding IsVisible}"/>
<Label DataContext="{Binding MyObject[2]}"
Content="{Binding MyText}"
Visibility="{Binding IsVisible}"/>
[...]
</Grid>
</Border>
It depends on how you are changing the amount of rows and labels.
I assume that MyObject is a List<MyObject>. In that case what you can do is simply bind the list to the Visibility property with a Converter that loops through the objects checking if they are all invisible.
XAML:
Namespace:
xmlns:converters="clr-namespace:MyConverters"
Window:
<Window.Resources>
<converters:ObjectBorderVisibilityConverter
x:Key="MyObjectBorderVisibilityConverter"/>
</Window.Resources>
<Border BorderBrush=Black
BorderThickness="{Binding MyObject, Converter={StaticResource MyObjectBorderVisibilityConverter}">
[...]
Converters Code:
namespace MyConverters
{
public class ObjectBorderVisibilityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility v = Visibility.Hidden;
List<MyObject> myObjects = value as List<MyObject>;
foreach(Object myobject in myObjects)
{
if (myobject.IsVisible)
v = Visibility.Visible;
}
return v;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new InvalidOperationException("ObjectBorderVisibilityConvertercan only be used OneWay.");
}
}
}
Otherwise you are going to have to explain how you got the amount of rows and labels to be dynamic and we can work from there.
Hope this helps
u_u
EDIT
Well according to your comment you have a list of strings which contain the name of the object you want to display in each ListViewItem. I'm not going to ask why you are doing it this way, I assume you have a reason. I just wanna say have you tried Key Value pairs?
What I would do here is pass the grid itself as a parameter in the converter, and loop through its children using a LogicalTreeHelper inside the converter.
Revised Border:
<Window.Resources>
<converters:ObjectBorderVisibilityConverter
x:Key="MyObjectBorderVisibilityConverter"/>
</Window.Resources>
<Border BorderBrush=Black
BorderThickness="{Binding MyObject, Converter={StaticResource MyObjectBorderVisibilityConverter}", ConverterParameter={Binding ElementName=myGrid, BindsDirectlyToSource=True>
<Grid x:Name="myGrid">
[...]
Revised Converter
namespace MyConverters
{
public class ObjectBorderVisibilityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility v = Visibility.Hidden;
Grid myGrid = parameter as Grid;
List<MyObject> myObjects = value as List<MyObject>;
foreach (var child in LogicalTreeHelper.GetChildren(myGrid))
{
if(child.GetType() == typeof(System.Windows.Controls.Label)
if (((Label)child).Visibility = Visibility.Visible)
v = Visibility.Visible;
}
return v;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new InvalidOperationException("ObjectBorderVisibilityConvertercan only be used OneWay.");
}
}
}
I coded this all by hand so there's prolly a bunch of errors, but I hope you get the point.
u_u

Binding a datacontext string property to a StaticResource key

I have an List values with a ResourceKey and a Caption, these values are both strings. The Resource is the name of an actual resource defined in a resource dictionary. Each of these ResourceKey Icons are Canvas's.
<Data ResourceKey="IconCalendar" Caption="Calendar"/>
<Data ResourceKey="IconEmail" Caption="Email"/>
I then have a list view which has a datatemplate with a button and a text caption below the button. What I want to do is display Resource static resource as the content for the button.
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Content="{Binding ResourceKey}" Template="{StaticResource RoundButtonControlTemplate}"/>
<TextBlock Grid.Row="1" Margin="0,10,0,0" Text="{Binding Caption}" HorizontalAlignment="Center" FontSize="20" FontWeight="Bold" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
I think I have tried every permutation with binding staticresource etc.
I am open to alternatives, I know it may be easier to just have an image and set the source property.
Thanks
After having a little think I ending up using a ValueConvertor like so:
class StaticResourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var resourceKey = (string)value;
return Application.Current.Resources[resourceKey];
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new Exception("The method or operation is not implemented.");
}
}
and the binding on the button becomes
<Button Content="{Binding ResourceKey, Converter={StaticResource resourceConverter}}" />
Here I've got an improved version of #dvkwong 's answer (along with #Anatoliy Nikolaev 's edit):
class StaticResourceConverter : MarkupExtension, IValueConverter
{
private Control _target;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var resourceKey = (string)value;
return _target?.FindResource(resourceKey) ?? Application.Current.FindResource(resourceKey);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
var rootObjectProvider = serviceProvider.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider;
if (rootObjectProvider == null)
return this;
_target = rootObjectProvider.RootObject as Control;
return this;
}
}
usage:
<Button Content="{Binding ResourceKey, Converter={design:StaticResourceConverter}}" />
The primary change here is:
The converter is now a System.Windows.Markup.MarkupExtension so it can be used directly without being declared as a resource.
The converter is context-aware, so it will not only look up in your App's resources, but also local resources (current window, usercontrol or page etc.).

Resources