I have a combobox which I want to call a method from MainViewModel but it binds to EmployeesOverviewViewModel. Is it possible to do this? if yes - how?
Here is my code for the combobox
<ComboBox ScrollViewer.CanContentScroll="False" Text="Select Employees" DataContext="{Binding EmployeesOverviewViewModel, Source={StaticResource ViewModelLocator}}" Name="employeeComboBox" ItemsSource="{Binding Employees}">
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=IsSelected}" Content="{Binding Path=Name}" Width="{Binding ElementName=employeeComboBox, Path=ActualWidth}" VerticalAlignment="Center">
</CheckBox>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I have thought about using Command but I couldn't figure out the binding problem.
BR
if your MainViewModel is anywhere is the visual tree as the DataContext, then you can achieve what you want with RelativeSource in your CommandBinding for your ComboBox.
In expanding on my comment to the original post. Shown below is an example of how to bind to the data context of the parent.
Command="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=DataContext.SomeCommand}"
Set the path to command on the viewmodel you want to bind to.
Do both ViewModels know each other? Then the EmployeesOverviewViewModel could provide an delegate that you would execute and the MainWindowViewModel could use this delegate to "bind" it to its method. (edit: it would be enough if the MainWindowViewModel knows the EmployeesOverviewViewModel)
Otherwise you could try to use a binding using FindAncestor and try to get the MainWindowView. The problem then would be that you don't just need the view itself but its DataContext.
I would say you have two realistic approaches.
1) if your view can see a suitable instance of MainViewModel, you should be able to bind to a command or whatever you need on that by using StaticResource or DynamicResource. I see you're using a StaticResource to find the viewmodel providing the ComboBox's items, would something similar work for finding MainViewModel?
2) if your view can't see a MainViewModel, but your viewmodel can, get the viewmodel to expose a suitable command or method and just have that call MainViewModel's version. This is cleaner, as then your EmployeesOverviewView doesn't have to know anything about MainViewModel at all.
I'd prefer option 2.
You can do that using a MultiValueConverter. I show you a small sample.
I have a window with 3 CheckBox:
<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="300" Width="400" mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:WpfApplication7="clr-namespace:WpfApplication7" d:DesignHeight="371"
d:DesignWidth="578" SizeToContent="WidthAndHeight">
<Window.Resources>
<WpfApplication7:MultiBooleanConverter x:Key="multiBooleanConverter" />
</Window.Resources> <Grid>
<CheckBox Content="Hallo">
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource ResourceKey=multiBooleanConverter}">
<Binding ElementName="checkBox1" Path="IsChecked"/>
<Binding ElementName="checkBox2" Path="IsChecked"/>
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
<CheckBox x:Name="checkBox1" Content="CheckBox" Height="16" HorizontalAlignment="Left" Margin="64,72,0,0" VerticalAlignment="Top" />
<CheckBox Content="CheckBox" Height="16" HorizontalAlignment="Left" Margin="62,120,0,0" x:Name="checkBox2" VerticalAlignment="Top" />
</Grid>
</Window>
The MultiValueConverter is declared like that:
public class MultiBooleanConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values.Cast<bool>().Any(b => b);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
object[] returnValue = new object[targetTypes.Length];
for (int i = 0; i < targetTypes.Length; i++)
{
returnValue[i] = (bool)value;
}
return returnValue;
}
}
Related
I have a ComboBox that has an ItemsSource bound to an ObservableCollection. I would like to have a NONE value appended to the front of Collection, on the View only. I do not want to actually add this appended value to the bound Collection, only for the ComboBox items. I have been trying ComboBoxItems but that doesn't seem to work, as it won't actually add.
This is my XAML:
<ContentControl Content="{Binding Developer.Games}" Height="25" Width="177">
<ContentControl.ContentTemplate>
<DataTemplate>
<Grid>
<ComboBox x:Name="cb" ItemsSource="{Binding}" DisplayMemberPath="Date"/>
<TextBlock x:Name="tb" Text="Select Game" IsHitTestVisible="False" Visibility="Hidden" TextAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<DataTemplate.Triggers>
<Trigger SourceName="cb" Property="SelectedItem" Value="{x:Null}">
<Setter TargetName="tb" Property="Visibility" Value="Visible"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
So, I would want my Collection to look like this on the expanded drop-down:
NONE
Game1
Game2
Game3
I do not want to actually add this appended value to the bound Collection
The short answer is what you bind to your data source is what you see from the control.
With that in mind, what you should do in your case is simply not bind the data source from the outside, but make a new data source with your extra items internally (meaning inside the custom derived class you should be working on) and bind that instead. You just have to make sure you keep your data source in sync with the outer data source, using the standard observable events.
WPF has a way of changing values between the VM and the view using IValueConverter. You can do something like this:
public class GameListEmptyOptionValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var v = value as ObservableCollection<Game>;
v?.Insert(0, new Game() { Name = "NONE" });
return v;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
and, to use it, on your view:
<Window.Resources>
<local:GameListEmptyOptionValueConverter x:Key="GameListEmptyOptionValueConverter"/>
</Window.Resources>
<Grid>
<ComboBox ItemsSource="{Binding ., Converter={StaticResource GameListEmptyOptionValueConverter}}" DisplayMemberPath="Name"/>
</Grid>
You can use a CompositeCollection.
Here is an example based on the XAML code you provided, that adds a ListBoxItem with the text "NONE" as the first item and displays the rest of the objects in the view model.
<ComboBox x:Name="cb">
<ComboBox.Resources>
<CollectionViewSource x:Key="GamesCollection" Source="{Binding}"/>
</ComboBox.Resources>
<ComboBox.ItemsSource>
<CompositeCollection>
<ListBoxItem>NONE</ListBoxItem>
<CollectionContainer Collection="{Binding Source={StaticResource GamesCollection}}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
This is my first time building a UWP app and I'm new to c#/Windows in general. I am trying to use a Pivot in the UI. I want the pivot headers to be from an ObservableCollection of usb devices connected, which go by the class Device_Info. Each USB Device has a property called HardwareRevNumMajor that I would like to display as each pivots header. My xaml looks like this:
<Page
x:Class="usb_test.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:usb_test"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:code="using:usb_test"
mc:Ignorable="d">
<Page.DataContext>
<local:View_Model/>
</Page.DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Pivot x:Name="pivot1" Title="Pivot" Opacity="0.99" ItemsSource="{Binding Devices}">
<Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<Binding Path="Device_Info.HardwareRevNumMajor"/>
</TextBlock.Text>
</TextBlock>
<!--<TextBlock Text="{Binding HardwareRevNumMajor}">
</TextBlock>-->
</DataTemplate>
</Pivot.HeaderTemplate>
<Pivot.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding DeviceFiles}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding numBlocks}"/>
<TextBlock Text="{Binding syncTime}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
</Grid>
As soon as a Device_Info object gets added to the Devices observableCollection I get an error. Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)). Then if I click in my MainPage.xaml file in the designer I see this:
TargetException: Object does not match target type.
StackTrace:
at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj,
BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
InnerException: None
You can see from the xaml above that I've tried a number of ways to display the HarwareRevNumMajor property that lives on a Device_Info by the commented out TextBlock code.
My ViewModel looks like this:
namespace usb_test
{
public class View_Model
{
public ObservableCollection<Device_Info> _devices;
public ObservableCollection<File_Info> _deviceFiles;
public CoreDispatcher _dispatcher;
public View_Model() {
_devices = new ObservableCollection<Device_Info>();
_deviceFiles = new ObservableCollection<File_Info>();
}
public ObservableCollection<Device_Info> Devices
{
get
{
return _devices;
}
}
public ObservableCollection<File_Info> DeviceFiles
{
get
{
return _deviceFiles;
}
}
In My MainPage.xaml.cs I have this:
namespace usb_test
{
public sealed partial class MainPage : Page
{
Device_List devList = new Device_List();
Device_Structure deviceStruct = new Device_Structure();
View_Model viewModel = new View_Model();
public MainPage()
{
this.InitializeComponent();
viewModel._dispatcher = Dispatcher;
this.DataContext = viewModel;
devList.devices.CollectionChanged += this.OnCollectionChanged;
deviceStruct.deviceFiles.CollectionChanged += this.OnCollectionChanged;
...
This line of code is what adds a device to the list:
await viewModel._dispatcher.RunAsync(CoreDispatcherPriority.Normal, async() => { devList.devices.Add(devInfo); });
This line succeeds and adds a Dev_Info object into the devices observableCollection and shortly after the application crashes.
I'm sure there are more errors when I try to display File Info stuff later in the xaml but I'd really appreciate just getting the pivot header to display correctly. Like I said I'm very new to this so I'm assuming there are a number of problems, I'd appreciate any advice/clarity into what is stopping me from not being able to display a property from a Dev_Info object.
Thanks!
Your items from Devices are of type Device_Info. In your DataTemplate your bind the text property to Device_Info.HardwareRevNumMajor. Since the context is your item (Device_Info), you try to access a property Device_Info.
If your write:
<TextBlock Text="{Binding HardwareRevNumMajor}" />
You try to access the property HardwareRevNumMajor wich probably exists in Device_Info.
Thanks for the suggestions above. I made some progress.
I rewrote my xaml like this:
<Page
x:Class="usb_test.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:usb_test"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:code="using:usb_test"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Pivot x:Name="pivot1" Title="Pivot" Opacity="0.99" ItemsSource="{x:Bind viewModel.Devices}">
<Pivot.HeaderTemplate>
<DataTemplate x:DataType="local:Device_Info">
<TextBlock Text="{x:Bind HardwareRevNumMajor}"></TextBlock>
</DataTemplate>
</Pivot.HeaderTemplate>
<Pivot.ItemTemplate>
<DataTemplate x:DataType="local:Device_Info">
<ListView ItemsSource="{x:Bind devStruct.deviceFiles}" Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:File_Info">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Red" Text="{x:Bind fileName}" HorizontalAlignment="Center" Margin="0,0,20,0"/>
<TextBlock Foreground="Red" Text="{x:Bind numBlocks}" HorizontalAlignment="Center" Margin="0,0,20,0"/>
<Button Content="Download File" Click="{x:Bind onDownloadClick}" HorizontalAlignment="Center" Margin="0,0,20,0">
</Button>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
</Grid>
You'll notice I took out the
<Page.DataContext>
<local:View_Model/>
</Page.DataContext>
from my previous xaml code.
Then I used ItemsSource="{x:Bind viewModel.Devices}"> in the Pivot. viewModel is defined in my MainPage.xaml.cs and is an instance of the View_Model class I created above. Then from there I added a DataType to DataTemplate which is a Device_Info and then I could easily access an attribute of the Device_Info object, in this case HardwareRevNumMajor.
The PivotItemTemplate is a little more confusing. The class Device_Info has a property on it called devStruct which is a class I created (Device_Struct). An instance of Device_Struct has an ObservableCollection of File_Info objects. So this collection tells us the files on the device and it's called deviceFiles. That is the collection I wanted to use inside the Pivot Items. I'm not sure if there's a way to do this without inserting a <ListView> into the XAML but this is what I found works. With this I can now display information about the files on each Pivot Item.
I also switched from using Binding to x:Binding. To be honest I'm not sure exactly why that helped but when I used Binding I was getting: Object reference not set to an instance of an object. If anyone has a better understanding of that, I'd love to hear about it. Thanks again!
So I have a view, containing a telerik RadGridView, this view is bound to several items, but importantly I need to bind the visibility of an item in one column, to 2 items.
The converter will correctly evaluate the visility, however I need to pass back the previousProc, (currently handled) and also "This" which is a proc as well, just that row.
<telerik:RadGridView Name="ProcedureGrid"
DockPanel.Dock="Left"
SelectionMode="Single"
SelectionUnit="FullRow"
ItemsSource="{Binding Procedures}"
IsReadOnly="True"
AutoGenerateColumns="False"
ShowGroupPanel="False"
ShowColumnHeaders="False"
CanUserReorderColumns ="False"
RowIndicatorVisibility="Collapsed"
Visibility="Collapsed"
Width="200"
FontSize="18"
SelectionChanged="ProcedureGrid_SelectionChanged"
>
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Header="Name"
AllowDrop="False"
DataMemberBinding="{Binding Converter={StaticResource langConverter}}"
IsGroupable="False"
IsFilterable="False"
MaxWidth="155"/>
<telerik:GridViewColumn>
<telerik:GridViewColumn.CellTemplate>
<DataTemplate>
<nav:SmallForwardNavigateIcon MaxWidth="30" DockPanel.Dock="Right" Margin="1"
Cursor="Hand" VerticalAlignment="Center" HorizontalAlignment="Center"
MouseDown="SmallForwardNavigateIcon_MouseDown"
Visibility="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl}},
Path=DataContext.previousProc,
Converter={StaticResource IsPrevProc}}" />
</DataTemplate>
</telerik:GridViewColumn.CellTemplate>
</telerik:GridViewColumn>
</telerik:RadGridView.Columns>
</telerik:RadGridView>
can anyone see where I went wrong and what I could do to fix the xaml to pass both the previousproc and This back
If I understand your UserControl host a telerik:RadGridView control.
Your UserControl has a given DataContext, which seems to conatin a property Procedures, and a property IsPrevProc.
Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}},Path=DataContext.previousProc,Converter={StaticResource IsPrevProc}}" />
This code seems wrong because you write:
Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}
It means you are looking for properties in your ancestor DataContext, the one containing Procedures and IsPrevProc. So all bindings here have to be with properties of this DataContext. You can't mix in one binding call to different DataContext.
What you could do is create your "previousProc" as a property in this DataContext, so that you can call it directly.
Or you can define "IsPrevProc" as a property of the DataContext of a line of your Grid.
But you can't do both in the same binding.
The ConverterParameter property is not a dependency property and hence can not be bound.
There is however an alternative solution. You could use a MultiBinding with a multi-value converter instead of a normal Binding:
<nav:SmallForwardNavigateIcon MaxWidth="30" DockPanel.Dock="Right" Margin="1"
Cursor="Hand" VerticalAlignment="Center" HorizontalAlignment="Center"
MouseDown="SmallForwardNavigateIcon_MouseDown"
>
<nav:SmallForwardNavigateIcon.Visibility>
<MultiBinding Converter="{StaticResource IsPrevProc}">
<Binding Path="DataContext.previousProc" RelativeSource="{RelativeSource Mode=FindAncestor,
AncestorType=UserControl}"/>
<Binding Path="DataContext.newProc" RelativeSource="{RelativeSource Mode=Self}"/>
</MultiBinding>
</nav:SmallForwardNavigateIcon.Visibility>
</nav:SmallForwardNavigateIcon>
Pass the new proc/this value in second binding.(use relative source if needed)
MultiValue Converter:
public class IsPrevProc : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//Logic of new proc and Previous Proc
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I Have a WPF treeview and i need the reference of parent node in the child node context.
menu command. In the below XAML, i need to pass the reference of A in member command parameter
XAML:
<DataTemplate x:Key="Member">
<TextBlock Text="{Binding}" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=mylib:ExtendedTreeView}}">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.Tag.DeleteMmeberCommand}">
<MenuItem.CommandParameter>
<MultiBinding Converter="{StaticResource MutilValueConverter}">
<Binding Path=".."/>
<Binding />
</MultiBinding>
</MenuItem.CommandParameter>
</MenuItem>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
<HierarchicalDataTemplate DataType="{x:Type A}" ItemsSource="{Binding Members}" ItemTemplate="{StaticResource Member}"
<TextBlock Text="{Binding"}>
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.Tag.DeleteACommand}" CommandParameter="{Binding}"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</HierarchicalDataTemplate>
<TreeView ItemsSource="{Binding As}"/>
Converter:
public class MutilValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
If i understand correctly, you could possibly invert the whole thing:
publish your command in what is your datacontext and give an instance
of your subdatacontext as command parameter (this is just Binding for
your items)
You are using PlacementTaregt in your bindings but you havent set the ContextMenu.PlacementTarget anywhere...
<TextBlock Text="{Binding"} x:Name="MyTextBox">
<TextBlock.ContextMenu>
<ContextMenu PlacementTarget="{Binding ElementName=MyTextBox}">
.....
the straight way is to have viewmodels for what your Members collection is holding.
and with child viewmodels, there is no need for getting in the binding, as you can just hold the data needed in the viewmodel class. it is an adapter between your model (whereever the strings come from) and your view (where the strings are displayed).
Since you apparently can't create a Silverlight DataTemplate in C#, I'm trying to create one in XAML. I have a converter that I need to refer to, that I have defined in C# in another namespace. I've tried doing this:
<UserControl.Resources>
<DataTemplate x:Key="PriceTemplate">
<TextBlock Text="{Binding Price, Converter={Converters:PriceConverter}}" />
</DataTemplate>
</UserControl.Resources>
Where Converters is an xmlns that points to the correct namespace. However, I get a compilation error that says:
Type 'Converters:PriceConverter' is
used like a markup extension but does
not derive from MarkupExtension.
I tried adding System.Windows.Markup.MarkupExtension as a parent to my converter, but it apparently doesn't exist in Silverlight.
How can I refer to my converter in XAML, without having to rewrite it in XAML?
You want to make a static resource first, then bind to the converter that is a static resource.
<UserControl.Resources>
<conv:IntConverter x:Key="IntConverter"></conv:IntConverter>
</UserControl.Resources>
<StackPanel>
<TextBlock x:Name="Result" Margin="15" FontSize="20"
HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{Binding Converter={StaticResource IntConverter}}">
</TextBlock>
</StackPanel>
</Window>
So the "conv:" xml namespace was registered at the top of the document like you do with custom controls:
xmlns:conv="clr-namespace:MyFooCompany.Converters"
This example is adapted from the below linked tutorial regarding the same issue for WPF:
http://www.dev102.com/2008/07/17/wpf-binding-converter-best-practices/
You seem to be confusing Types with Instances. A converter type will exist "in" a namespace however in binding we do not specify a type as the converter. Instead we give the binding an actual instance of that type.
Generally IValueConverter instances are stateless, hence we can hold a common instance anywhere in a the chain of resource dictionaries available where the instance of a DataTemplate is loaded.
In xaml we can reference another namespace by creating a new alias to cover it. With that in mind your xaml could look something like this:-
<UserControl x:Class="SilverlightApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SilverlightApplication1"
xmlns:localConverters="clr-namespace:SilverlightApplication1.Converters">
<UserControl.Resources>
<localConverters:PriceConverter x:Key="PriceConverter" />
<DataTemplate x:Key="Test">
<TextBlock Text="{Binding Price, Converter={StaticResource PriceConverter}}" />
</DataTemplate>
</UserControl.Resources>
<RadioButton GroupName="Group1">
<RadioButton.Template>
<ControlTemplate>
<ToggleButton IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<ToggleButton.Content>
<SymbolIcon Symbol="Edit"/>
</ToggleButton.Content>
<ToolTipService.ToolTip>
<ToolTip Content="Sample Tooltip" Placement="Mouse" />
</ToolTipService.ToolTip>
</ToggleButton>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
Adding to the answer posted by #Rokk.
In addition to the other answers suggesting creating an instance of the ValueConverter in a resource dictionary, another solution is to implement it via a MarkupExtention:
public class IntToLetterConverter : IMarkupExtension<IValueConverter>, IValueConverter
{
public IValueConverter ProvideValue(IServiceProvider serviceProvider)
=> (IValueConverter)this;
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
=> ((IMarkupExtension<IValueConverter>)this).ProvideValue(serviceProvider);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> (char)('a' + (int)value);
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> (int)((char)value - 'a');
}
With this solution you can directly reference the converter (which is in essence a MarkupExtension) whithout defining a resource.