Selecting all items after binding wpf listview - wpf

I have the following XAML:
<ListView x:Name="debitOrderItems" ItemsSource="{Binding DebitOrderItems}">
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox x:Name="checkbox" Content="{Binding}" IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Binding a list of items works fine and I get a beautiful listview with checkboxes, but I would like to have them all selected immediately. There is a SelectAll() method on the ListView, but when can I call it? DataContextChanged does not work as I link it before I populat the DebitOrderItems on it.

You can do this in the Loaded event:
public Window()
{
InitializeComponent();
Loaded += delegate
{
_listView.SelectAll();
};
}
That said, I'd question your design. Normally you would have a view model for each item in the list, and you would bind the IsChecked property to a property on that view model.

Related

Cannot change appearance of "{NewItemPlaceholder}" in WPF combobox

I have bound an ObservableCollection<Company> to a combobox.
<ComboBox
IsEditable="True"
Text="{Binding Path=Company.CompanyName, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding Path=CompanyCollection,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ucEventDialog}}}"
SelectedItem="{Binding Path=Company}"
HorizontalAlignment="Stretch"/>
During runtime WPF adds at the end of the bound list an additional ComboboxItem {NewItemPlaceHolder} to the dropdown list.
I would like to use this item to trigger an additional dialog box to add a new item to the collection.
I tried to create a template for this additional item using <ComboBox.Resources> ...
<ComboBox.Resources>
<DataTemplate x:Key="PlaceholderTemplate">
<TextBlock Text="New..."/>
</DataTemplate>
</ComboBox.Resources>
However I have not found any means to ...
Change the appearance of the {NewItemPlaceHolder}.
Trigger an event when the {NewItemPlaceHolder} is selected.

WPF: DataTemplate not applied to dynamically added ListBoxItems

I'm creating a UserControl that contains a Listbox. I want the User to be able to add new Listbox Items through a ButtonClick. Adding the new Items works fine but it seems that my DataTemplate is not applied to the newly added Item.
This is how I assign my DataTemplate:
<ListBox x:Name="UserControlListBox" ItemsSource="{Binding Path=ItemsSource, ElementName=MyCustomListControl}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock TextTrimming="CharacterEllipsis" Text="{Binding}"
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualWidth}" HorizontalAlignment="Left"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is how I add a new ListboxItem:
public void AddItem(object listBoxItem)
{
IEnumerable enumerable = ItemsSource;
List<object> asList = enumerable.Cast<object>().ToList();
asList.Add(listBoxItem);
ItemsSource = asList;
}
I need a TextBox around my ListItem-Content in order to use the TextTrimming-Property. It works fine for the Items that are already inside the List that is assigned to the ItemSource Property of my UserControl but not to the ones that are added through the ButtonClick as you can see
here

How do I get all rows from dataGrid that have a combobox checked

<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<CheckBox Name="CheckALL" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="chkDiscontinue" IsChecked="{Binding Path=IsChecked, ElementName=CheckALL, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I can click the header check-box and make all check-boxes selected, But Here, I need to Get all selected grids bind to 'IsChecked'
Well in datacontext of this view you can get desired by doing this --
Your_Item_Source.Where(p=>p.Checked)
In your OrderHeader class, create a property
public bool IsSelected {get;set;} // with inotify please
then bind your combobox chkDiscontinue to
{Binding IsSelected}
Bind your Header checkbox to ViewModel Property
public bool SelectAll {get;set;} // with inotify please
In setter of this property, set all OrderHeader.IsSelected = value in AllOrderHeader, and in getter your can return status of items in the AllHeaders
In addition to what Muds said, if you want bind IsChecked to SelectAll, you should use something like that :
Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}, Path= DataContext.SelectAll}
Sorry for not posting as reply but I dont have enough points :)

Binding ComboBox to DataGrid Entry

Solved problem, but still have questions. See end of post, or read on for context.
I'm trying to setup a WPF datagrid which has many templated columns with comboboxes inside of them. In particular I'm having trouble with data-binding.
Data Model
First, I have Entry, which contains 4 properties:
Name
Customer
Color
Type
The most interesting property is Color which has two more sub properties:
ColorString
Index
Goal
I need to create a data grid where each row corresponds to an Entry object. The Customer, Color, and Type properties all have comboboxes that allow for a selection of dynamically populated choices. I need the selected item for each combobox to bind to the entry's respective property.
Screenshot
Questions:
How do I properly set the data contexts for the data grid and for each combobox?
For the data grid, I'm setting the data context programmatically to an instance of ObservableCollection.
private ObservableCollection<Entry> entries = new ObservableCollection<Entry>();
public MainWindow()
{
InitializeComponent();
entries.Add(new Entry("Foo", "Customer1", new MyColor("#00000000", 1), "Type1"));
entries.Add(new Entry("Bar", "Customer2", new MyColor("#00000000", 1), "Type2"));
LayerMapGrid.DataContext = entries; //Set data-context of datagrid
}
For the color combobox, I'm using an ObjectDataProvider in my XAML:
<Window.Resources>
<ObjectDataProvider x:Key="Colors" ObjectType="{x:Type local:MyColor}" MethodName="GetColors"/>
</Window.Resources>
This is how I bind the ObjectDataProvider
<ComboBox ItemsSource="{Binding Source={StaticResource Colors}}"/>
In the MyColor class, I've created the method below:
public static ObservableCollection<MyColor> GetColors()
{
ObservableCollection<MyColor> colors = new ObservableCollection<MyColor>();
//... Fill collection... (omitted for brevity)
return colors;
}
The good news is that ALL of the above code WORKS. However is it a good approach to the problem at hand?
This my next and more important question:
How do I bind the selected items of the comboboxes so that ObservableCollection<Entry> is updated?
I'm aware that I need to set the UpdateSourceTrigger="PropertyChanged", so that my source, which is the Entry collection is updated.
Here is my current XAML code for setting up my entire data grid. Note: I haven't implemented the customer and type comboboxes yet. I'm really just concerned with the color combobox:
<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False" Name="LayerMapGrid">
<DataGrid.Columns>
<!--Name Column-->
<DataGridTemplateColumn Header="Name">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Control.HorizontalContentAlignment" Value="Center" />
</Style>
</DataGridTemplateColumn.HeaderStyle>
</DataGridTemplateColumn>
<!--Customer Column-->
<DataGridTemplateColumn Header="Customer">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding CustomerName, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!--Color Column-->
<DataGridTemplateColumn Header="Color">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource Colors}}" SelectedItem="{Binding Color, ElementName=LayerMapGrid, UpdateSourceTrigger=PropertyChanged}">
<ComboBox.ItemTemplate>
<DataTemplate>
<DockPanel Margin="2">
<Border DockPanel.Dock="Left" HorizontalAlignment="Right" BorderThickness="1" BorderBrush="Black" Margin="1" Width="10" Height="10">
<Rectangle Name="ColorRec" Fill="{Binding ColorString}"/>
</Border>
<TextBlock Padding="4,2,2,2" Text="{Binding ColorString}" VerticalAlignment="Center"/>
</DockPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!--Type Column-->
<DataGridTemplateColumn Header="Type">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding Type, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Your assistance is greatly appreciated. I've been banging my head on the wall for about 16 hours with this.
-Nick Miller
EDIT:
I found the solution (and as always immediately after requesting help), but I don't understand how it works.
In the XAML, I've changed the combobox binding to be the following:
<ComboBox ItemsSource="{Binding Source={StaticResource Colors}}" SelectedItem="{Binding Color, UpdateSourceTrigger=PropertyChanged}">
What exactly is happening here?
Why is the combobox now referring to the datagrid's data context? Doesn't that get overriden when I set the ItemsSource to point to my ObjectDataProvider?
How do I properly set the data contexts for the data grid and for each combobox?
You don't. Normally in WPF, we set the DataContext property on the UserControl, or Window that we are designing, not on individual controls. In this way, all the controls in the view have access to the data properties.
How do I bind the selected items of the comboboxes so that ObservableCollection is updated?
Again, you don't do what you are doing. Rather than using an ObjectDataProvider, you should just have a property of type ObservableCollection<MyColor> in the code behind and bind to that directly. And you should be binding a public Entries property to the DataGrid.ItemsSource property, not setting the private entries field as the DataContext. You really need to read through the Data Binding Overview page on MSDN for further help with this.
Set the DataContext of MainWindow.xaml to itself (which generally is a not a good idea):
public MainWindow()
{
InitializeComponent();
Entries.Add(new Entry("Foo", "Customer1", new MyColor("#00000000", 1), "Type1"));
Entries.Add(new Entry("Bar", "Customer2", new MyColor("#00000000", 1), "Type2"));
DataContext = this; //Set DataContext to itself so you can access properties here
}
Then in MainWindow.xaml:
<DataGrid ItemsSource="{Binding Entries}" ... />
The DataTemplates in each row of the DataGrid automatically have the relevant item in the data bound collection set as the DataContext, so you automatically get access to the properties from the relevant class. Again... no need to set any DataContexts manually. If you have further questions, please read the linked article, because the answers are there.
UPDATE >>>
Let's be clear about something... I am not your personal mentor, so this will be my last reply.
How do I overcome the combobox inheriting the data context of the data grid?
To data bind to the object that is set as the Window.DataContext, you just need to use a valid Binding Path and some basic logic:
<ComboBox ItemsSource="{Binding DataContext.MyColors, RelativeSource={RelativeSource
AncestorType={x:Type YourLocalPrefix:MainWindow}}}" />

Append DataGrid inside of DataGrids RowDetailsTemplate

this appears to bind, but rows in Details Grid are empty. Something is off/missing?
I've also tried {Binding SubCustomers}
SubCustomers is a List on parent object.
I am able to bind this way to single Fields such as FirstName etc.. just not the subcollection..
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Source=SubCustomers}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
The problem is that you are trying to bind to a property on the DataContext of the parent, not on that particular row. So, the DataContext of the RowDetails is the row item, and in order to get the parent's property, you need to use RelativeSource bindings. If you bind to the DataContext of the parent, you can then "dot-down" to the property you actually care about:
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<DataGrid AutoGenerateColumns="True"
ItemsSource="{Binding DataContext.SubCustomers, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>

Resources