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>
Related
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 have a WPF datagrid source which has CabinetName as property. I want the selected item to be this Cabinet name and the combobox dropdown to be filled from a new List FCabinetNames. I write this combobox template into my wpf datagrid to implement this functionality.
<DataGridTemplateColumn Header="Cabinet">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding CabinetName}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding FCabinetNames}"></ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
Now the selected item is showing up correctly so TextBlock Text part is fine. But the item source is not loaded fine.
I have this snippet for the item source.
public class FCabinetNames:List<string>
{
BusinessLogic admintasks = new BusinessLogic();
public FCabinetNames()
{
try
{
List<CabinetData> cab1 = admintasks.CabinetDataforGrid();
List<string> fcabinetname = new List<string>();
foreach (var c1 in cab1)
{
this.Add(c1.CabinetName);
}
}
catch
{
}
}
}
I cannot bind my sample data to textblocks in stackpanel, which I defined in resources. I think that I use style in wrong way, because I receive toString() method instead of class binded fields.
That's my resources with defined style:
<UserControl.Resources>
<ItemsPanelTemplate x:Key="VirtualizingStackPanelTemplate">
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
<ListView x:Key="ListBoxTemplate" HorizontalAlignment="Left" ScrollViewer.HorizontalScrollBarVisibility="Visible">
<ListView.ItemTemplate>
<DataTemplate>
<!--<ListBoxItem Background="DarkOrchid" Margin="1,1, 5,5" Height="400" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch">-->
<StackPanel>
<TextBlock FontSize="30" Text="{Binding Title}"/>
<TextBlock FontSize="20" Text="{Binding Desc}"/>
</StackPanel>
<!--</ListBoxItem>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</UserControl.Resources>
Here is my method in which i add listview programatically:
long rowCount = ContentGridFullView.RowDefinitions.LongCount();
if (rowCount > 8) return;
var c1 = new RowDefinition { Height = new GridLength(1, GridUnitType.Star) };
ContentGridFullView.RowDefinitions.Add(c1);
rowCount = ContentGridFullView.RowDefinitions.LongCount();
TextBlock tb = new TextBlock {Text = "TEXTBLOCK ITEM = " + (rowCount - 1), FontSize = 40};
Viewbox vb = new Viewbox { Child = tb };
if (rowCount > 8) return;
Grid.SetRow(vb, Convert.ToInt32(rowCount-1));
Grid.SetColumn(vb, 1);
ListView lb = new ListView();
lb.Style = Resources["ListBoxTemplate"] as Style;
lb.ItemsPanel = (ItemsPanelTemplate) Resources["VirtualizingStackPanelTemplate"];
var products = new ObservableCollection<Product>() { new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC") };
lb.ItemsSource = products;
ContentGridFullView.Children.Add(lb);
ContentGridFullView.Children.Add(vb);
Grid.SetRow(lb, Convert.ToInt32(rowCount - 1));
Grid.SetColumn(lb, 2);
And my short class that I want to bind:
public class Product
{
public string Title { get; set; }
public string Desc { get; set; }
public Product(string title, string desc)
{
Title = title;
Desc = desc;
}
public override string ToString()
{
return "I see that message instead of Title and Desc";
}
}
Can someone tell me what's wrong with this code? Thank you.
Create your Observable collection as a property (getter/setter):
ObservableCollection<Product> _products;
public ObservableCollection<Product> products
{
get{return _products;}
set
{
_products=value;
PropertyChanged("products");
}
}
The property changed event will be need to indicate that the collection has changed,its needed when your using ObservableCollection. You'll need to read more about it.You can add items to the products collection by using :
products.Add(Product_object)
And your xaml code will have the itemsSource as follows:
<ListView x:Key="ListBoxTemplate" HorizontalAlignment="Left" ScrollViewer.HorizontalScrollBarVisibility="Visible" ItemsSource="{Binding products}">
<ListView.ItemTemplate>
<DataTemplate>
<!--<ListBoxItem Background="DarkOrchid" Margin="1,1, 5,5" Height="400" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch">-->
<StackPanel>
<TextBlock FontSize="30" Text="{Binding Title}"/>
<TextBlock FontSize="20" Text="{Binding Desc}"/>
</StackPanel>
<!--</ListBoxItem>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The following statement is important in your xaml code so that your xaml code will know where to look for the data.
DataContext="{Binding RelativeSource={RelativeSource Self}, Path=x}
First try and create a static list and check if data is getting initialized properly and then you can try creating listviews dynamically. But the code above will be the same thing you will have to do create dynamic listviews.
I have a listbox with a data template bound to a list<class> in the program.
<DataTemplate x:Key="pTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Ref}" Padding="5,0,0,0"/>
<StackPanel Name="taggedA" Tag="{Binding A}" Orientation="Horizontal">
<TextBlock Name="selectedA" Text="{B}" />
</StackPanel>
<Image Name="ind" Width="40" Height="40" />
</StackPanel>
</DataTemplate>
On button click, I want to go over all the elments of the listbox and check if the stackPanel taggedA's tag == textblock selectedA's text.
This is to be done for each of the items in the list box and the data template is as above. How can this be done?
Easier to compare the binding source directly:
ListBox l = myListBox;
for (int i = 0; i < l.Items.Count; i++)
{
var boundObject = (MyClass)l.Items[i];
MessageBox.Show("They are equal? " + (boundObject.A == boundObject.B));
}
I would agree with #dbaseman. But if you are set on doing it you could do the following:
private void button_click(object sender, RoutedEvent e)
{
foreach(var item in MyListBox.Items)
{
ListBoxItem lbi = MyListBox.ItemContainerGenerator.ContainerFromItem(item);
StackPanel taggedApanel = (lbi.Content as StackPanel).Children[1];
//Do whatever you need to do here
}
}
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;
}
}