I'm trying to use Caliburn.Micro to bind a view model of a nested ListBox but I'm stuck.
I have a list workspace that is divided in two sections a list of groups containtaining items in a different part of that workspace I want to show the details of either a group or an item in a group depending on what is the SelectedItem. I'm new to Caliburn.Micro and looked at the documentation and samples but don't know how to connect the dots. Specifically I'm trying to model this after the Caliburn.Micro.HelloScreens sample. The code I have so far:
The ViewModel:
public class AnalyzerGroupWorkspaceViewModel : Conductor<AnalyzerGroupWorkspaceViewModel>, IWorkspace
{
private Selected selected = Selected.AnalyzerGroup;
private const string name = "Analyzers";
public AnalyzerGroupWorkspaceViewModel(
IMappingEngine fromMapper,
IRepository<Model.AnalyzerGroup> analyzerGroups)
{
AnalyzerGroups = new ObservableCollection<IAnalyzerGroupViewModel>(analyzerGroups.GetAll().Select(fromMapper.Map<Model.AnalyzerGroup,AnalyzerGroupViewModel>));
}
public ObservableCollection<IAnalyzerGroupViewModel> AnalyzerGroups { get; private set; }
public string Name { get { return name; } }
public Selected Selected
{
get { return selected; }
set
{
if (value == selected) return;
selected = value;
NotifyOfPropertyChange(() => Selected);
}
}
private IConductor Conductor { get { return (IConductor) Parent; } }
public void Show()
{
var haveActive = Parent as IHaveActiveItem;
if (haveActive != null && haveActive.ActiveItem == this)
{
DisplayName = name;
Selected = Selected.AnalyzerGroup;
}
else
{
Conductor.ActivateItem(this);
}
}
}
The view:
<UserControl x:Class="Philips.HHDx.SSW.AnalyzerGroup.AnalyzerGroupWorkspaceView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<DockPanel>
<GroupBox Header="AnalyzerGroups" DockPanel.Dock="Top">
<ListBox x:Name="AnalyzerGroups">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}" />
<ListBox x:Name="Analyzers">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Id }"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</GroupBox>
<GroupBox Header="Details">
<ContentControl cal:View.Context="{Binding Selected, Mode=TwoWay}"
cal:View.Model="{Binding}"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"/>
</GroupBox>
</DockPanel>
</UserControl>
Next to that I have two UserControls that display the detailsof a group or item.
My specific question is how can I use the SelectedItem property of the two ListBoxes to modify the Selected property to switch between displaying the AnalyzerGroup details and the Analyzer details?
I've found the solution to the above described problem the solution consists of four parts:
Add a IsSelected property (that notifies changes) to both 'child' ViewModels
Bind the IsSelected property of the ListBox.ItemContainerStyle to the IsSelected property of the respective ViewModels
Attach a Caliburn.Micro Message to the 'outer' ListBox and use the $eventArgs argument
In the ViewModel bound to the entire UserControl implement the method corresponding to the Message and use the AddedItems property of the eventArgs to set the SelectedViewModel property setting the IsSelected property of the previous SelectedViewModel to false
The code then becomes:
The ViewModel:
public class AnalyzerGroupWorkspaceViewModel : PropertyChangedBase, IAnalyzerGroupWorkspaceViewModel
{
private IAnalyzerViewModel selectedViewModel;
private const string WorkspaceName = "Analyzers";
public AnalyzerGroupWorkspaceViewModel(
IMappingEngine fromMapper,
IRepository<Model.AnalyzerGroup> analyzerGroups)
{
AnalyzerGroups = new ObservableCollection<IAnalyzerGroupViewModel>(
analyzerGroups.GetAll().Select(
fromMapper.Map<Model.AnalyzerGroup, AnalyzerGroupViewModel>));
}
public void SelectionChanged(object eventArgs)
{
var typedEventArgs = eventArgs as SelectionChangedEventArgs;
if (typedEventArgs != null)
{
if (typedEventArgs.AddedItems.Count > 0)
{
var item = typedEventArgs.AddedItems[0];
var itemAsGroup = item as IAnalyzerViewModel;
if (itemAsGroup != null)
{
SelectedViewModel = itemAsGroup;
}
}
}
}
public ObservableCollection<IAnalyzerGroupViewModel> AnalyzerGroups { get; private set; }
public string Name { get { return WorkspaceName; } }
public IAnalyzerViewModel SelectedViewModel
{
get { return selectedViewModel; }
set
{
if (Equals(value, selectedViewModel))
{
return;
}
if (SelectedViewModel != null)
{
SelectedViewModel.IsSelected = false;
}
selectedViewModel = value;
NotifyOfPropertyChange(() => SelectedViewModel);
}
}
}
The View:
<UserControl x:Class="Philips.HHDx.SSW.AnalyzerGroup.AnalyzerGroupWorkspaceView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<DockPanel>
<GroupBox Header="AnalyzerGroups" DockPanel.Dock="Top">
<ListBox SelectionMode="Single"
x:Name="AnalyzerGroups"
cal:Message.Attach="[Event SelectionChanged] = [Action SelectionChanged($eventArgs)]">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="DarkGray">
<StackPanel Orientation="Vertical" Margin="10">
<TextBlock Text="{Binding Name}" />
<ListBox SelectionMode="Single" ItemsSource="{Binding Analyzers}" >
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="DarkGray">
<StackPanel>
<TextBlock Text="{Binding Name }" Margin="10" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</GroupBox>
<GroupBox Header="Details">
<ContentControl cal:View.Model="{Binding SelectedViewModel}" />
</GroupBox>
</DockPanel>
</UserControl>
The answer to your specific question is yes, you can.
On the ViewModel of your UserControl. You create a property that is a ViewModel of either of the two details.
public interface IAnalyzerViewModel
{
}
Next, create two ViewModels for the Views of your Analyzer and AnalyzerGroup views.
public class AnalyzerGroupViewModel : IAnalyzerViewModel
{
}
public class AnalyzerViewModel : IAnalyzerViewModel
{
}
Next, create a property in your UserControl's ViewModel that implements INPC or PropertyChangedBase of Caliburn Micro.
public class MainViewModel :
{
private IAnalyzerViewModel _analyzerViewModel;
public IAnalyzerViewModel SelectedViewModel { get { return _analyzerViewModel; } set { _analyzerViewModel = value; OnPropertyChanged(() => SelectedViewModel); }
//Hook up the selected item changed event of your listbox and set the appropriate ViewModel to show, so if you either want to show the AnalyzerGroup or AnalyzerView.
}
And lastly, just update your MainView to
<ContentControl x:Name="SelectedViewModel"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"/>
Caliburn will hook up the appropriate bindings and stuff and will pull the View for the associated ViewModel, and also the Name convention part will automatically map it to any public property of its datacontext as long as the names match.
Related
I'm trying to bind each view model in an ObservableCollection<FilterControlViewmodel> as DataContext to a user control FilterControl in an ItemsControl.
The binding itself works fine. "InitialFilterName" is displayed correctly from FilterControlViewmodel.FilterName but any updates on the property are not notified to the UI.
Also adding elements to ObservableCollection<FilterControlViewmodel> is working find and adding additional user controls. But again the values inside the FilterControlViewmodel are not updated to the UI.
Any hint on where the notification is missing is appreciated. Thanks.
MainWindow.xaml
<Window.DataContext>
<local:MainWindowViewmodel/>
</Window.DataContext>
<Grid>
<ItemsControl ItemsSource="{Binding FilterViewmodel.FilterControls}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<filter:FilterControl DataContext="{Binding}"></filter:FilterControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
FilterControl.xaml
<UserControl.DataContext>
<local:FilterControlViewmodel/>
</UserControl.DataContext>
<Grid>
<Label Grid.Column="0" Grid.Row="0" Content="{Binding FilterName}"></Label>
<ComboBox Grid.Column="0" Grid.Row="1" ItemsSource="{Binding FilterValues}" SelectedItem="{Binding FilterValueSelected}"></ComboBox>
<Button Grid.Column="1" Grid.Row="1" Content="X" Command="{Binding ResetFilterCommand}"></Button>
</Grid>
MainWindowViewmodel.cs
public class MainWindowViewmodel : INotifyPropertyChanged
{
public FilterViewmodel FilterViewmodel
{
get => _filterViewmodel;
set
{
if (Equals(value, _filterViewmodel)) return;
_filterViewmodel = value;
OnPropertyChanged();
}
}
FilterViewmodel.cs
public class FilterViewmodel : INotifyPropertyChanged
{
public ObservableCollection<FilterControlViewmodel> FilterControls
{
get => return _filterControls;
set
{
if (Equals(value, _filterControls)) return;
_filterControls = value;
OnPropertyChanged();
}
}
FilterControlViewmodel.cs
public class FilterControlViewmodel : INotifyPropertyChanged
{
private string _filterName = "InitialFilterName";
public string FilterName
{
get => _filterName;
set
{
if (value == _filterName) return;
_filterName = value;
OnPropertyChanged();
}
}
You should remove the following markup as it creates another instance of FilterControlViewmodel:
<UserControl.DataContext>
<local:FilterControlViewmodel/>
</UserControl.DataContext>
The FilterControl will then inherit its DataContext from the current item (FilterControlViewmodel) in the ItemsControl without you having to set the DataContext property explicitly:
<ItemsControl ItemsSource="{Binding FilterViewmodel.FilterControls}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<filter:FilterControl/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I'm creating a WPF application using MVVM pattern (at least I'm trying). There is <TabControl> with bound ItemsSource,which is an ObservableCollection<TabModel> Tabs. Tabs has Name and Items property, where Items is a list of ControlModel, which means Controls. I have problem with binding IsEnabled property to Grid where Items are placed.
Below there is a part of my code presenting the way I'm doing this:
private ObservableCollection<TabModel> tabs;
public ObservableCollection<TabModel> Tabs
{
get
{
if (tabs == null)
{
tabs = new ObservableCollection<TabModel>();
RefreshTabs();
}
return tabs;
}
set
{
tabs = value;
OnPropertyChanged("Tabs");
}
}
\\Tab Model
public string Name { get; set; }
private List<ControlModel> items;
public List<ControlModel> Items
{
get { return items; }
set
{
items = value;
OnPropertyChanged("Items");
}
}
And xaml...
<TabControl Margin="0,100,0,0" ItemsSource="{Binding Tabs,UpdateSourceTrigger=PropertyChanged}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<Grid Margin="5,5,5,5" IsEnabled="{Binding IsProductEditionEnabled}">
<!--<Grid Margin="5,5,5,5">-->
<ItemsControl ItemsSource="{Binding Items,UpdateSourceTrigger=PropertyChanged}" ItemTemplateSelector="{StaticResource ControlTemplateSelector}"/>
</Grid>
</ScrollViewer>
</DataTemplate>
</TabControl.ContentTemplate>
The part...
<Grid Margin="5,5,5,5" IsEnabled="{Binding IsProductEditionEnabled}">
is not working. There is no error. This grid is always disabled. By default it's false.
private bool isProductEditionEnabled = false;
public bool IsProductEditionEnabled
{
get { return isProductEditionEnabled; }
set
{
isProductEditionEnabled = value;
OnPropertyChanged("IsProductEditionEnabled");
}
}
The question is : How to bind IsEnabled in my case properly?
You are inside a DataTemplate so you need to specify where the parent DataContext is when you do the binding, something like this:
<DataTemplate>
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<Grid IsEnabled="{Binding Path=DataContext.IsProductEditionEnabled,
RelativeSource={RelativeSource AncestorType={x:Type TabControl}}}">
</Grid>
</ScrollViewer>
</DataTemplate>
I am using Caliburn.Micro in my C# WPF project and I have sucessfully used single selection binding in ListBox. How to use multiple selection in this scenario?
Xaml:
<ListBox x:Name="Items">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Time}"/>
<Label Content="{Binding Desc}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code:
public BindableCollection<MyObject> Items
{
get
{
var collection = new BindableCollection<MyObject>(_MyObject);
return collection;
}
}
public MyObject SelectedItem
{
get; set;
}
Add IsSelected property to your item:
public class MyObject : PropertyChangedBase
{
public DateTime Time { get; set; }
public String Desc { get; set; }
bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
NotifyOfPropertyChange();
}
}
}
Then add binding to this property to your ListBox:
<ListBox x:Name="Items" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Time}"/>
<Label Content="{Binding Desc}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
After that you may refer to selected items in your View Model:
BindableCollection<MyObject> _items = new BindableCollection<MyObject>();
public BindableCollection<MyObject> Items
{
get
{
return _items;
}
}
public BindableCollection<MyObject> SelectedItems
{
get
{
_selectedItems.Clear();
_selectedItems.AddRange(Items.Where(mo => mo.IsSelected));
return _selectedItems;
}
}
I'm trying to add buttons to UserControl. I have to follow MVVM pattern. I have created a class, DeviceButton, with different set/gets and a constructor. In a viewmodel, used as datacontext, is the ObservableCollection and a get-method for the collection. I have bound the collection to a ItemsControl source and tried to add a template. I guess I'm missing something 'cause the buttons won't load.
The UserControl is added into a tab (using dragablz) which as well is a part of a ObservableCollection, also added at run time (this is working just fine). The idea is, that the tab has a list of buttons that has to be created at run time, where the list is fetched from a web service - so the buttons has to be added dynamically/programatically. Overview is just the first tab - a template for each tab (reflecting the fetched items) is being implemented when the buttons work. For now, I'm just adding a test button to the collection, but as stated, this won't show. What am I missing?
I have a Overview.xaml file:
<UserControl // attributes omitted to save spaces... ask if needed>
<StackPanel>
<Border>
<TextBlock FontSize="16" FontWeight="Bold" TextWrapping="WrapWithOverflow"
TextAlignment="Center" HorizontalAlignment="Center"
Foreground="{DynamicResource AccentColorBrush}">
Welcome to Greenhouse App
</TextBlock>
</Border>
<ItemsControl ItemsSource="{Binding DeviceButtons}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type vmodel:DeviceButton}">
<Button Width="50" Height="50" Margin="10 10 0 0" Command="{Binding OpenTab}"
CommandParameter="{Binding DeviceType}" HorizontalAlignment="Left"
VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}">
<StackPanel>
<Image Source="{Binding ImageUrl}" />
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
// Manually added test button...
<Button x:Name="windMill" HorizontalAlignment="Left" Margin="10,0,0,0"
VerticalAlignment="Top" Width="50" Height="50"
Command="{Binding OpenTab}" FontFamily="Segoe Ui"
Style="{DynamicResource SquareButtonStyle}">
<StackPanel>
<Image Source="/Greenhouse;component/Icons/Windmill.png" />
</StackPanel>
</Button
</StackPanel>
I'm trying to add an ObservableCollection of type DeviceButton, the _deviceButtons collection (Binded as ItemsSource to the ItemsControl)
The tabList items are working just find, and I can manually add more if needed (these will later be added through the OpenNewTab-command, which should be bound to the buttons)
The DeviceButton file:
public class DeviceButton
{
private readonly string _content;
private readonly string _deviceType;
private readonly string _imageUrl;
public DeviceButton(string content, string deviceType, string imageUrl)
{
_content = content;
_deviceType = deviceType;
_imageUrl = imageUrl;
}
public string Content
{
get { return _content; }
}
public string DeviceType
{
get { return _deviceType; }
}
public string ImageUrl
{
get { return _imageUrl; }
}
}
The collection is located in a viewmodel file, MainWindowViewModel.cs:
public class MainWindowViewModel : ViewModelBase, INotifyPropertyChanged
{
public ICommand OpenTab { get; set; }
private string tabControl { get; set; } = "0";
private IInterTabClient _interTabClient;
private ObservableCollection<TabContent> _tabContents = new ObservableCollection<TabContent>();
private ObservableCollection<DeviceButton> _deviceButtons = new ObservableCollection<DeviceButton>();
public MainWindowViewModel()
{
_interTabClient = new MyInterTabClient();
DeviceButtons.Add(new DeviceButton("Windturbine", "windturbine", "/Greenhouse;component/Icons/Windmill.png"));
TabContents.Add(new TabContent("Overview", new Overview()));
OpenTab = new RelayCommand<object>(OpenNewTab);
}
private void OpenNewTab(object obj)
{
MessageBox.Show("Yo"); // Not yet implemented
RaisePropertyChanged(() => tabControl);
}
public ObservableCollection<TabContent> TabContents
{
get { return _tabContents; }
}
public ObservableCollection<DeviceButton> DeviceButtons
{
get { return _deviceButtons; }
}
public IInterTabClient InterTabClient
{
get { return _interTabClient; }
}
}
The buttons aren't loaded when I start the program (only the "test" button added manually in the WPF).
The UserControl, Overview, is considered a tab in another Controls.Metrowindow, MainWindow.xaml:
<Window.Resources>
<Style TargetType="{x:Type dragablz:TabablzControl}">
<Setter Property="CustomHeaderItemTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type viewmodel:TabContent}">
<TextBlock Text="{Binding Header}" />
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type viewmodel:TabContent}">
<ContentPresenter Margin="4" Content="{Binding Content}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<dragablz:TabablzControl SelectedIndex="{Binding tabControl}" ItemsSource="{Binding TabContents}" x:Name="InitialTabablzControl" Margin="4 0 4 4">
<dragablz:TabablzControl.InterTabController>
<dragablz:InterTabController InterTabClient="{Binding MyInterTabClient}" />
</dragablz:TabablzControl.InterTabController>
</dragablz:TabablzControl>
I guess it's an issue with the resources/binding in the Overview.xaml, but I've exhausted all suggested solutions I could find.
Issue was in binding
ItemsSource="{Binding Path=DataContext.TabContents,
RelativeSource={RelativeSource AncestorLevel=1,
AncestorType={x:Type Window}, Mode=FindAncestor}}"
I suspect the DataContext is being set to a TabContent object, which does not have a DeviceButtons property
I would suggest using a tool like Snoop to verify your DataContext is what you expect.
I'm trying to show collection of bool with a DataTemplate for ListView.
Here's the code:
In MainWindow.xaml
<Window.Resources>
<DataTemplate x:Key="ListItemCheckBoxTemplate">
<CheckBox IsChecked="{Binding Mode=OneWay}"/>
</DataTemplate>
<DataTemplate x:Key="ListItemRadioButtonTemplate">
<RadioButton IsChecked="{Binding Mode=OneWay}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="ListViewSample" />
<ListBox ItemsSource="{Binding MyData}" ItemTemplate="{StaticResource ListItemCheckBoxTemplate}" Grid.Column="1"/>
</Grid>
In MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class ViewModel
{
private List<bool> myBooleanCollection;
public List<bool> MyData
{
get { return myBooleanCollection; }
set { myBooleanCollection = value; }
}
public ViewModel()
{
myBooleanCollection = new List<bool>();
myBooleanCollection.Add(true);
myBooleanCollection.Add(false);
myBooleanCollection.Add(true);
myBooleanCollection.Add(true);
myBooleanCollection.Add(false);
}
}
Instead of ItemTemplate ListItemCheckBoxTemplate I want to apply ListItemRadioButtonTemplate with Radio button. How I can specify the use of ItemTemplate for the same source in xaml. Do I need to change the DataSource for the same or
do I have some way to specify the DataTemplate in xaml based on condition.
You did not specify what is the condition on which you want to change template but you can add another property to your view model, say AllowMultiple:
public class ViewModel: INotifyPropertyChanged
{
private List<bool> myBooleanCollection;
public List<bool> MyData
{
get { return myBooleanCollection; }
set { myBooleanCollection = value; }
}
private bool _allowMultiple;
public bool AllowMultiple
{
get { return _allowMultiple; }
set
{
if (_allowMultiple != value)
{
_allowMultiple = value;
OnPropertyChanged("AllowMultiple");
}
}
}
}
and then change ListBox.Style to:
<ListBox ItemsSource="{Binding MyData}">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Setter Property="ItemTemplate" Value="{StaticResource ListItemCheckBoxTemplate}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=AllowMultiple}" Value="False">
<Setter Property="ItemTemplate" Value="{StaticResource ListItemRadioButtonTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
assuming that ViewModel implements INotifyPropertyChanged you can then change ItemTemplate buy changing AllowMultiple against view model
You can specify DataTemplate for each item with the followign attribute:
ItemTemplate="{StaticResource ListItemCheckBoxTemplate}
Change this to:
ItemTemplate="{StaticResource ListItemRadioButtonTemplate}
If you need multiple item templates in the same ListBox then you can provide custom template selection logic via the DataTemplateSelector Class
If you want to do it in Xaml, you will need to expose property which you can bind to as a selector. Have a look at A Data Template Selector in Xaml
You need create DataTemplateSelector and using this for ItemTemplateSelector. You also need to determine the condition under which you will return the DataTemplate. Example:
XAML
<Window x:Class="YourNamespace.MainWindow" ...
xmlns:this="clr-namespace:YourNamespace"
<Window.Resources>
<DataTemplate x:Key="OneTemplate">
<CheckBox IsChecked="{Binding Mode=OneWay}" />
</DataTemplate>
<DataTemplate x:Key="SecondTemplate">
<RadioButton IsChecked="{Binding Mode=OneWay}" />
</DataTemplate>
</Window.Resources>
<ListBox ItemsSource="{Binding MyData}">
<ListBox.ItemTemplateSelector>
<this:MyItemTemplateSelector OneTemplate="{StaticResource OneTemplate}"
SecondTemplate="{StaticResource SecondTemplate}" />
</ListBox.ItemTemplateSelector>
</ListBox>
Code-behind
public class MyItemTemplateSelector : DataTemplateSelector
{
public DataTemplate OneTemplate { get; set; }
public DataTemplate SecondTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
bool myItem = (bool)item;
if (myItem == true)
{
return OneTemplate;
}
return SecondTemplate;
}
}