I'm using .Net 3.5 with WPF and XAML.
I have a datagrid with the first column being a DataGridCheckBoxColumn.
This is inside of a window popup.
In the constructor, I sometimes want to initialize all rows to be selected, and other cases no rows to be selected.
Using data binding, I can initialize the checkbox on a row to either checked or not checked.
But I can't get the header checkbox checked along with all the checks on the rows in the case when all rows are to be checked. How can I get to the checkbox?
<toolkit:DataGridCheckBoxColumn CellStyle="{StaticResource SingleClickEditing}" Visibility="{Binding exists}" Binding="{Binding Path=toTransfer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="False">
<toolkit:DataGridCheckBoxColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Checked="CheckBox_Checked" Unchecked="CheckBox_Checked"/>
</StackPanel>
</DataTemplate>
</toolkit:DataGridCheckBoxColumn.HeaderTemplate>
</toolkit:DataGridCheckBoxColumn>
I'm doing something like:
public MyPopupWindow()
{
InitializeComponent();
if(checkMode.Equals("all"))
{
// Check all the items
foreach (var item in bindList)
{
item.toTransfer = true;
}
// How to check the header checkbox?
}
I'm not sure if this is the best way to do this but you can do
<CheckBox Checked="CheckBox_Checked" Unchecked="CheckBox_Checked" Loaded="CheckBox_Loaded"/>
and
void CheckBox_Loaded(object sender, RoutedEventArgs e)
{
CheckBox checkBox = sender as CheckBox;
if(checkMode.Equals("all"))
{
checkBox.IsChecked = true;
}
}
Related
I have a ListBox, where the list element has a ComboBox, a TextBox and a slider. Depending on the selction of the ComboBox either the TextBox or the slider should be visible.
<ListBox Name="lstPWM" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<!-- more definitions -->
</Grid.ColumnDefinitions>
<ComboBox ItemsSource="{Binding Path=Gebertyp, Converter={local1:EnumToCollectionConverter}, Mode=OneTime}"
SelectedValuePath="Value"
DisplayMemberPath="Description"
SelectionChanged="PWMTyp_SelectionChanged"
SelectedValue="{Binding Path=Gebertyp}" />
<TextBox Visibility="{Binding GeberVisible}" Text="{Binding GeberNmr, Mode=TwoWay}"/>
<Slider Visibility="{Binding WertVisible}" Value="{Binding Wert, Mode=TwoWay}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The code behind is:
public partial class MainWindow : Window
{
public ObservableCollection<PWMKanal> PWM_col { get; set; } = new();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
lstPWM.ItemsSource = PWM_col;
foreach (var item in Board.PWM) PWM_col.Add(item); //Board.PWM is the data source.
}
private void PWMTyp_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBox box = sender as ComboBox; // Finding the line in the ListBox.
PWMKanal PWM = box.DataContext as PWMKanal;
int z = PWM_col.IndexOf(PWM);
Board.PWM[z].Gebertyp = (QuellePWM)box.SelectedValue;
if (Board.PWM[z].Gebertyp == QuellePWM.Sender)
{
PWM_col[z].GeberVisible = Visibility.Visible; // I thought that i may change the
PWM_col[z].WertVisible = Visibility.Hidden; // ObservableColelction directly
} // but the display is not updated.
else // In Debug mode i see, that PWM_coll
{ // is changed as expected, but no effect
PWM_col[z].GeberVisible = Visibility.Hidden; // on the GUI.
PWM_col[z].WertVisible = Visibility.Visible;
}
if (PWM_col.Count != 0) // this code is intended to update the GUI, but every time
{ // a new item is added the Selection Change fires again
PWM_col.Clear(); // and i get a stack overflow in an endless loop.
foreach (var item in Board.PWM) PWM_col.Add(item);
}
}
}
The comments describe my approaches and problems:
I change the selected element of the ObservableCollection directly, but this has no effect on GUI. At least tho code doesn't crash.
I clear the list ObservableCollection PWM_col, but then i get an infinite loop: every time an element is added to the list the SelectionChange event fires, calling the routin again. Result is stack overflow.
Now my questions to my approaches:
Is it possible to change an element of an ObservableCollection directly by code, and the display is automatically refreshed?
Is it possible to somehow catch the SelectionChanged event before the handler is executed? Or is it possible to temporary dissable the event?
Any other idear?
Thank you for your help!
CollectionChanged does notify, that collection itself, not the
single items, is changed. Therefore to see the changes item's
property need to implement INotifyPropertyChanged. Also remove Mode=OneTime
You can of course set the flag, that PWMTyp_SelectionChanged is
running:
private bool selChangedIsRunning = false;
private void PWMTyp_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(selChangedIsRunning) return;
selChangedIsRunning = true;
// do stuff ....
selChangedIsRunning = false;
}
Other idea is - don't use the SelectionChange event, but do bind
Slider.Visibility and TextBox.Visibility to the
ComboBox.SelectedValue and use value converter to define the
Visibilty, also you can use the ConverterParameter.
<ComboBox x:Name="CmbPWMTyp" ItemsSource="{Binding Path=Gebertyp, Converter={local1:EnumToCollectionConverter}, Mode=OneTime}"
SelectedValuePath="Value"
DisplayMemberPath="Description"
SelectionChanged="PWMTyp_SelectionChanged"
SelectedValue="{Binding Path=Gebertyp}" />
<TextBox Visibility="{Binding ElementName=CmbPWMTyp, Path=SelectedValue, Converter={StaticResource YourConverter}, ConverterParameter=TBX}" Text="{Binding GeberNmr, Mode=TwoWay}"/>
<Slider Visibility="{Binding ElementName=CmbPWMTyp, Path=SelectedValue, Converter={StaticResource YourConverter}, ConverterParameter=SLDR}" Value="{Binding Wert, Mode=TwoWay}"/>
This link can be also very helpful for you: Difference between SelectedItem SelectedValue and SelectedValuePath
So I am having an issue where I have a GridView's ItemsSource bound to a collection of object. I also have a column of Check boxes that can be used to select object the user wishes to remove and all related items. The problem I am having is that when the user selects one item, I get stuck in a loop of the items being continually selected. Does anyone have an idea on how I can stop the programmatic selection of these check boxes from firing the Checked event.
Property in use:
List<MyObject> _localCollection = new List<MyObject>();
List<MyObject> LocalCollection
{
get { return _localCollection; }
set
{
_localCollection = value;
OnPropertyChanged("LocalCollection");
}
}
Loose example of XML code:
<GridView Name="grdItems">
<GridViewColumn>
<GridViewColumn.Header>
<CheckBox/>
</GridViewColumn.Header>
<!--Column Template-->
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Tag="{Binding ObjID}"
IsChecked="{Binding ToRemove, Mode=OneWay}"
Checked="SelectRelative" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
The "SelectRelative" method looks as follows:
private void SelectRelative(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke((Action)(() =>
{
//Get the Object Id we need
int selectedId = Convert.ToInt32(((CheckBox)sender).Tag);
//Get all objects that share this ID
List<MyObjects> objLst = new List<MyObjects>(((IEnumerable<MyObjects>)grdItems.ItemsSource));
//Clear the local collection property of our items used in the items source
LocalCollection.Clear();
//Remove the items source since we are updating it
grdItems.ItemsSource = null;
//Go through each item in the list and if the object id's match select them to remove
foreach(var item in objLst)
{
if(item.ObjId == selectedId)
item.ToRemove = true;
//Add the object to our property
LocalCollection.Add(item);
}
//Re-establish the item source with our new collection
grdItems.ItemsSource = LocalCollection;
}));
}
try this:
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="chkboxPaid" Checked="chkboxPaid_Checked" Content="check" Style="{StaticResource MaterialDesignCheckBox}" IsChecked="{Binding Path=IsSelected, Mode=TwoWay,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGridRow}}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
I would like to be able to get and set the state of a checkbox in a listview. I would like to either be able to automatically update MyListItems[row].myCheckedValue when the box is clicked by somehow binding in xaml (I know very little about binding) or to be able to loop through each list item by row and access the checkboxes in C#. I don't know how to approach either. I'm just starting out with WPF.
I Could also use Checked and Unchecked events, but I don't know how to retrieve the row of the list item the checkbox is in.
<ListView Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox x:Name="checkBox" Checked="itsChecked" Unchecked="itsUnchecked"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public List<myListItem> MyListItems;
...
listView.ItemsSource = MyListItems;
...
public class myListItem {
public bool myCheckedValue;
}
private void getCheckedItems() {
//Loop through listview rows and get checkbox state
//???
}
private void itsChecked(object sender, RoutedEventArgs e) {
//How can I get the row this checkbox is in??
}
something like
<GridViewColumn Header="Selected">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="chk" IsChecked="{Binding MyListItemsBoolField}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
assuming that your listView.ItemsSource = MyListItems; will stay
It should be as simple as binding IsChecked property of the CheckBox to a property on the ViewModel (you may need to add a new property if it doesn't already exist).
I using a ComboBox with CheckBox as ItemTemplate and I want to iterate through all items, get their checked status and write their content to a string if checked is true. The problem is that I am using a SqlDataReader to fill and bind the ComboBox from database and I can't find a way to access the items IsChecked property.
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Click="CheckBox_Click" Content="{Binding}" IsChecked="{Binding Path=IsSelected, Mode=TwoWay}" Tag="{RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I have tried casting the ComboBox items as CheckBoxes on the click event of them this way:
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < myComboBox.Items.Count; i++)
{
CheckBox cb = (myComboBox.Items[i] as CheckBox);
if (cb.IsChecked == true)
{
myString += "," + myComboBox.SelectedItem.ToString() + "";
}
}
}
but cb always returns NULL. I am guessing it is something with the IsChecked property binding.
I'd like to get this working but I don't want to create an object/class to fill the combobox because I need it to be filled with database. I'd really appreciate any help.
You could do something like this (I'm not stick to MVVM pattern) and this is written on the fly :
public ArrayList List { get; set; }
public MainWindow()
{
InitializeComponent();
SqlDataReader rdr = cmd.ExecuteReader();
List = new ArrayList();
while (rdr.Read()){
List.Add(new Class{ Id = rdr.GetString(0), Value = rdr.GetString(1), IsChecked= rdr.GetString(1) as bool}); //this class will contain the same data schema in your datareader but using properties
}
rdr.Close();
DataContext = List;
}
<ComboBox Name="ComboBox" ItemsSource="{Binding}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Tag="{Binding Id}" Content="{Binding Name}" IsChecked="{Binding IsChecked}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I have a DataGrid Shipments and Products. The shipments are always shown, and the products for each shipment are shown in a RowDetails, that becomes visible when I doubleclick a row.
In the DataGrid I am using a custom checkbox column:
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
Copy
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=DoCopy, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
My <DataGrid.RowDetailsTemplate> has the same column.
What I'm looking for, is to check all items in the details view when the "main" checkbox is checked.
I have a Shipment class and a Product class. Both classes have DoCopy property.
Shipment:
Run through all products and set DoCopy = true
Problem:
When I click a checkbox in the DataGrid, all products' checkboxes are checked. But only if the RowDetails are not shown. If the RowDetails are shown and I click the "main" checkbox, it gets checked, but the details checkboxes doesn't.
Also if I previously have opened and closed a row details and then check the "main" checkbox, the same happens. The products' checkboxes remain unchecked.
Shipment have a List<Product> which contains all products for that shipment.
Any ideas?
The following code works for me. I simply want to select all the check box of a datagrid on some event. The following code simply checked all the check boxes inside a datagrid. In my case column zero is a checkbox column
private void SelectAll()
{
for (int i = 0; i < dgVehicle.Items.Count; i++)
{
DataGridRow row = (DataGridRow)dgVehicle.ItemContainerGenerator.ContainerFromIndex(i);
if (row != null)
{
CheckBox chk = dgVehicle.Columns[0].GetCellContent(row) as CheckBox;
chk.IsChecked = true;
}
}
}
thakrage,
the easiest way to handle this, use click event for every "copy" checkbox row, in that event you can set Docopy=true or watever you like to do...
then define a check box outside a datagrid and then set the margin to place the checkbox exactly as like Data Header and bubble a click event to check all the rows.
refer my sample code below:
<CheckBox Name="chkbox_chkall" Click="chkbox_chkall_Click" Content="Check all" BorderBrush="#FF828282" Foreground="#FF5B585A"/>
and
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=DoCopy, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" Click="chkBoxRow_Click"
</DataTemplate>
in CodeBehind:
private void chkbox_chkall_Click(object sender, RoutedEventArgs e)
{
CheckBox chkbox_chkall = sender as CheckBox;
foreach (OnlineActivatedProducts rowItem in (grdProducts.ItemsSource))
{
CheckBox chk = grdProducts.Columns[6].GetCellContent(rowItem) as CheckBox;
if (chkbox_chkall.IsChecked == true)
{
chk.IsChecked = true;
}
else
{
chk.IsChecked = false;
}
chkBoxRow_Click(chk, e); // which bubbles each rows checked / unchecked event
}
}
private void chkBoxRow_Click(object sender, RoutedEventArgs e)
{
if (chkBoxContent.IsChecked.Value)
{
//if checked do something here
}
else if (!chkBoxContent.IsChecked.Value)
{
//if unchecked do something here
}
}
I got it, guys.
I seems I forgot to implement INotifyPropertyChanged.
It all works as it should now. Thanks :-)