I have three viewmodels:
AccountListViewModel(has a collection of accountviewmodels and a selectedaccount property)
public ObservableCollection<AccountViewModel> AccountList
public AccountViewModel SelectedAccount
AccountViewModel(has a collection of transactionviewmodel)
public ObservableCollection<TransactionViewModel> Transactions
and a TransactionViewModel.
I set the datacontext of the mainwindow to the AccountListViewModel and I have two Usercontrols(AccountListView and TransactionListView) that I set in the mainwindow as content control.
<DataTemplate x:Key="AccountListTemplate" >
<views:AccountListView />
</DataTemplate>
<DataTemplate x:Key="TransactionListTemplate" >
<views:TransactionListView />
</DataTemplate>
<ContentControl Content="{Binding}" ContentTemplate=" {StaticResource AccountListTemplate}" />
<ContentControl Grid.Row="1" Content="{Binding SelectedAccount}" ContentTemplate="{StaticResource TransactionListTemplate}" />
This is the itemssource of the AccountListView usercontrol
<ListView x:Name="AccountList" ItemsSource="{Binding Source={StaticResource GroupedAccounts}}" SelectedItem="{Binding SelectedAccount}" >
and the itemssource for the TransactionListView usercontrol
<ListView ItemsSource="{Binding Transactions}" >
The AccountList is displaying correctly but when I select an account no transactions are displayed although the logic is correct I think.
The Content property of the contentcontrol that holds the TransactionListView is set to SelectedAccount and the TransactionListView itemsource is the Transactions collection so whenever i click an account the transactions collection of that account should be displayed in the second contentcontrol.
Try using SelectedValue instead of SelectedItem and see if that works. You may also have to change your mode to two-way and update your source trigger.
<DataGrid ItemsSource="{Binding Source}"
SelectedValue="{Binding Selected}"
Margin="10">
<DataGrid.Columns>
<DataGridCheckBoxColumn Header="Test Checked" Binding="{Binding S}"/>
</DataGrid.Columns>
</DataGrid>
This is an example of a data grid, but the same concepts apply.
Related
I have a RadGridView with a GridViewToggleRowDetailsColumn, which can expand a selected item and show more Details. I want to use CaliburnMicro to Display the DetailsView, so I add a property of the DetailsViewModel to my "MainViewModel" and add a ContentControl with a Binding to it.
<telerik:RadGridView ItemsSource="{Binding Products.View}"
SelectedItem="{Binding SelectedProduct}" ... >
<telerik:RadGridView.RowDetailsTemplate>
<DataTemplate>
<ContentControl cal:View.Model="{Binding ProductDetailsViewModel}" />
</DataTemplate>
</telerik:RadGridView.RowDetailsTemplate>
<telerik:RadGridView.Columns>
<telerik:GridViewToggleRowDetailsColumn />
...Columndefinitions...
<telerik:RadGridView.Columns>
</telerik:RadGridView>
The problem is, that the Details are not displayed. From here I read that the binding fails because of the ItemsSource. So i tried
<ContentControl cal:View.Model="{Binding ProductDetailsViewModel, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" />
but it still does not work.
If the ProductDetailsViewModel property is the defined in the same class as the Products property that the RadGridView is bound to, try this:
<ContentControl cal:View.Model="{Binding DataContext.ProductDetailsViewModel, RelativeSource={RelativeSource FindAncestor, AncestorType=telerik:RadGridView}}" />
I want to display the content of a collection in a datagrid cell. What is special, is that the columnheaders are bound to a specific item of collection (i.e. one for each workday). The cell content should be a textbox for each employee in the according collection. The columnheaderpart is working fine.
The hierarchy of the viewmodel is as follows:
Planning holds a collection of Projects and a collection of Days(used to get the columnheader)
Project holds a collection of Days
Day holds a collection of Employees
However, the following code is not working. From debugging I'm lead to believe that the it is a problem with binding, as there is no access to the employees collection. Any idea why this is not working?
<DataGrid Grid.Row="0" Grid.Column="1" AutoGenerateColumns="False" ItemsSource="{Binding Planning.Projects}" ColumnHeaderHeight="50">
<DataGrid.Columns>
<DataGridTextColumn Width="200" Header="Project" Binding="{Binding Projectname}">
</DataGridTextColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<TextBlock DataContext="{Binding DataContext.Week.Days[0].Id, RelativeSource={RelativeSource AncestorType=DataGrid}}" HorizontalAlignment="Center">
<Run Text="{Binding Mode=OneWay, StringFormat=ddd}"/>
<LineBreak/>
<Run Text="{Binding Mode=OneWay, StringFormat=dd.MM.yyyy}"/>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding DataContext.Planning.Projects.Days[0].Employees}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The DataContext for the Cell DataTemplate is probably one instance of Project, because the ItemsSource for the DataGrid is a collection called Projects.
Therefore, in the CellTemplate, any Path on a Binding should be referring to a property of a Project, just as in the Projectname column:
<DataGridTextColumn
Width="200"
Header="Project"
Binding="{Binding Projectname}">
Project is the DataContext for each column. The above Binding works because Projectname is a property of Project.
So this should work:
<ItemsConttrol
ItemsSource="{Binding Days[0].Employees}"
...
Project has a Days collection. You want the Employees collection from the first item in Days for this project.
So I have a few ListViews. The first is binded to ObservaleCollection<ComPort>. All properties of ComPort may take some predefined values. Other ListViews are responsible for that properties: they show all that possible (predefined) values and SelectedItem should be the current value of that property of ComPort from the first ObservaleCollection.
I can't attach images so here is an external picture, it would make the situation clean: http://i.stack.imgur.com/ZBRRx.png
<Window.Resources>
<ResourceDictionary x:Name="rd">
<l:ComPorts x:Key="vComPorts"/>
<l:SystemPorts x:Key="vSystemPorts"/>
<l:BaudRates x:Key="vBaudRate"/>
<l:Parities x:Key="vParities"/>
<l:DataBits x:Key="vDataBits"/>
<l:StopBits x:Key="vStopBits"/>
<l:Timeouts x:Key="vTimeouts"/>
<l:ComPort x:Key="vSelectedPort"/>
</ResourceDictionary>
</Window.Resources>
...
<ListView
Name="PortsList"
Grid.Row="1"
Grid.Column="0"
Margin="5"
VerticalAlignment="Stretch"
ItemsSource="{StaticResource vComPorts}"
DataContext="{StaticResource vComPorts}"
SelectedValuePath="PortName"
SelectedValue="{Binding ElementName=SystemPortsList, Path=SelectedItem.Value}"
SelectionChanged="PortsList_SelectionChanged"
MouseDoubleClick="PortsList_MouseDoubleClick">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox />
<TextBlock Margin="5,0,0,0" Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView
x:Name="SystemPortsList"
Margin="5"
VerticalAlignment="Stretch"
DataContext="{Binding Source={StaticResource vSelectedPort}}"
ItemsSource="{Binding Source={StaticResource vSystemPortsView}}"
SelectedItem="{Binding Source={StaticResource vSelectedPort}, Path=PortName}"
MouseEnter="SystemPortsList_Refresh"
MouseLeave="SystemPortsList_Refresh"
Grid.Row="1"
Grid.Column="1" SelectionChanged="SystemPortsList_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Name="tb" Margin="5,0,0,0" Text="{Binding Path=Name}" />
</StackPanel>
</ListView.ItemTemplate>
</ListView>
I've tried to make an instance of class ComPort for saving current value of selected item from the first ListView, but anyway I can't cope with it without help. How this task should be solved?
1) Instead of handling SelectionChanged on the PortsList ListView, bind your checkbox to the ListViewItemsPanel like so:
<CheckBox IsChecked={Binding IsSelected, RelativeSource=Parent/>
2) Add an x:Name to your first ListBox, say x:Name="ComPortLB";
3) Remove DataContext on SystemPortsList;
4) Fix SelectedItem on SystemPortsList like so:
SelectedValue="{Binding ElementName=ComPortLB, Path=SelectedValue.PortName}"
I haven't tested any of this code and I haven't done this kind of stuff for a while, so I apologize for errors, but it should get you closer. I've also had to make some assumptions about your classes since you don't provide enough information.
I have two ListView, each bound to a specific collection in my ViewModel and I want to be able to select only one item globally.
Each ListView has its SelectedItem property bound to the same property in the ViewModel.
My probleme is as follow: when I select an item in a ListView, and then select another item in the other ListView, the first item stays selected.
I could achieve this with some code-behind, but I want to know if a pure XAML solution exists.
XAML:
<ListView SelectionMode="Single" ItemsSource="{Binding Path=MyList1}" SelectedItem="{Binding Path=MySelectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView SelectionMode="Single" ItemsSource="{Binding Path=MyList2}" SelectedItem="{Binding Path=MySelectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I finally got it working, by just replacing SelectedItem by SelectedValue.
In this use case, both properties have the same behaviour, but the latter one handles correctly the unselection if the bound selected item is not in the list.
You need to use Mode=TwoWay in your SelectedItem. It should work.
I have a DataTemplate that is loading a list of ~7000 items in a list for a combobox. Currently the ItemsSource is bound to a property in the data context of the DataTemplate, however this means that for each instance of the DataTemplate the system is loading all 7k objects, which is slowing down the system by quite a bit.
Ideally I want to be able to load the list once and use it for all instances. The obvious solution to me is using a resource defined in the Window.Resources section. However I can't figure out how this should work, and more importantly, how that resource should be populated via the MVVM pattern.
Current code which loads the ItemsSource for each DataTemplate instance
<DataTemplate>
<ComboBox SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding ItemsSource}" />
</DataTemplate>
Attempt at solving the problem:
<Window.Resources>
<ResourceDictionary>
<sys:Object x:Key="ItemItemsSource" />
</ResourceDictionary>
</Window.Resources>
<DataTemplate>
<ComboBox SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding Source={StaticResource ItemItemsSource}}" />
</DataTemplate>
Update
Each DataTemplate has its own DataContext which means each instance of the data template has its own ItemsSource, which will populate at DataContext initialiser.
Update 2
The ideal way in my mind to solve this is to have a property in the DataContext/VM of the Window that they Combobox is bound too. Is this possible? Something like:
public class WindowsViewModel
{
public List<Object> SharedItemSource { get; set; }
}
<DataTemplate>
<ComboBox SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding <Some Binding To SharedItemSource>}" />
</DataTemplate>
Where is the slow down ?
If it is when you show the ComboBox's popup, maybe you can try to use virtualization like this :
<DataTemplate>
<ComboBox SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding ItemsSource}">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
</DataTemplate>
Create a MainViewModel for your window or what ever control all your combobox's are in ,
cs:
public class MainViewModel
{
private List<object> _itemsSource;
public List<object> ItemsSource
{
get { return _itemsSource; }
set { _itemsSource = value; }
}
}
xaml:
<DataTemplate>
<ComboBox SelectedItem="{Binding SelectedItem}"
ItemsSource="{Binding Path=DataContext.ItemsSource,
RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>
</DataTemplate>
If you have property defined in VM, then that will be loading just once when you will be instantiating it and be served as source for all the comboboxes.. not every combobox create its itemsSource.. it just consume it to generate its items.. so whether you put your itemsSource as Resource or in Datacontext is one and the same thing here.