How to read dynamical added check box? - silverlight

I am adding checkboxes dynamically to silverlight stackpanel object as follows:
foreach (String userName in e.Result)
{
CheckBox ch = new CheckBox();
ch.Name = userName;
ch.Content = userName;
ContentStackPanel.Children.Add(ch);
}
How do I read back those controls to detect which of them are checked.

You can use databinding to checkbox list. Something like this:
Use a Listbox to create the check list:
<ListBox x:Name="chkList" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<CheckBox Content="{Binding userName}" IsChecked="{Binding Checked, Mode=TwoWay}"></CheckBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Then in your code just set the chklist itemSource to an ObservableCollection with your object
chkList.ItemsSource = ....

You should probably avoid creating checkboxes in code like this. Something that might be useful for you is a mini "ViewModel" for the checkbox. Something like this:
public class Option
{
public string Text {get; set;}
public bool IsChecked {get; set;}
}
Then, you can have a collection of these options like this:
var options = new ObservableCollection<Option>();
Once this is populated, you can bind the ObservableCollection to an ItemsControl:
<ItemsControl ItemsSource="{Binding options}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Text}" IsChecked="{Binding IsChecked}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
That XAML will create the CheckBoxes for you for ever option you added to your options collection. The really great thing is that you can now ask you options collection which options have been selected:
var selectedNames = from option in options
where option.IsChecked
select option.Text;
Using data binding and templates is a technique you should get familiar with in Silverlight/WPF. It is a really important concept, and it will let you do amazing things in you application.

Related

How to pass index of an ItemsSource as CommandParameter in WPF

In WPF:
How can i pass the index of a ItemsSource loop as a CommandParameter?
<ItemsControl ItemsSource="{Binding PageList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand, ElementName=Window}"
CommandParameter="INDEX OF ACTUAL ITEM AT ITEMSSOURCE GOES HERE" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
So, what i want is to pass the pushed button number to the Command method.
Thank you!
Simple way to do it.
First, screw indexes. They suck. Bind to SelectedItem
<ItemsControl ItemsSource="{Binding PageList}" SelectedItem="{Binding SelectedPage}">
Now, you don't have to try and pass the index into the parameter, because the selected page is already in your ViewModel.
// set in the ctor
public ObservableCollection<Page> PageList {get;private set;}
// Omitting INPC stuff in the setter
public Page SelectedPage {get;set;}
// Here's the Execute method of the ICommand
private void ExecuteChangePageCommand(object parameter)
{
// lol screw the parameter
var currentPage = SelectedPage;
UpdateSelectedPageOrDoWhateverLolKthx(currentPage);
}

Dynamically add child expander

Is there a way to create child expanders like this xaml bellow, at run-time?
<Expander Header="Building" IsExpanded="True">
<StackPanel>
<Expander Header="Sales">
<StackPanel>
<TextBlock>6100</TextBlock>
<TextBlock>6101</TextBlock>
<TextBlock>6111</TextBlock>
<TextBlock>6150</TextBlock>
</StackPanel>
</Expander>
<Expander Header="Director">
<StackPanel>
<TextBlock>6102</TextBlock>
<TextBlock>6113</TextBlock>
</StackPanel>
</Expander>
</StackPanel>
</Expander>
Set a name for first StackPanel (MainStackPanel) under the top Expander.
// Add new expander, stack panel and text block.
var newExpander = new Expander {Name = "NewExpander", Header = "New Expander"};
var newstackPanel = new StackPanel {Name = "NewExpanderStackPanel"};
var newtextBlock = new TextBlock {Text = "777"};
// Add above items as children.
newstackPanel.Children.Add(newtextBlock);
newExpander.Content = newstackPanel;
MainStackPanel.Children.Add(newExpander);
The best way would probably be to use data binding. I'm assuming you have some data structure that describes which expanders you want to create. Let's assume we have:
class Building
{
public List<Item> Items { get; }
public string Name { get; }
}
class Item
{
public int Number { get; }
}
In our user control, we'll set the DataContext to a list of Buildings (e.g. in the constructor):
DataContext = GetListOfBuildings();
Then we'd use two nested ItemsControls with templates to create the controls at runtime:
<Expander Header="Building"
IsExpanded="True">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding Name}">
<ItemsControl ItemsSource="{Binding Items}"
DisplayMemberPath="Number" />
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander>
This way you would not need to create controls in C#, which is more cumbersome in WPF.
Not quite sure about what you want to achieve.
If I understand correctly, you can save your code in a .xaml file as resource and use application to load it. Then, add the object to the visual tree.
var expander = (Expander) Application.LoadComponent(new Uri("UriToTheXamlFile"));
control.AddChild(expander);

Display Dynamic Number in WPF TabItem Header

I have a TabControl where every item contains a User Control called Timeline. This "Timeline" has a property called "Number" which changes during runtime.
I want to make the property "Number" to be displayed in the TabItem header. And i have really no idea how to do that to be honest.
My first thought is that i have to create a Custom Control that derives from the original TabItem Control and create a DependencyProperty or something with a custom ControlTemplate.
I feel that i'm pretty bad on explaining this...
An example: I Want to do something like the third image in the post on following url, but instead of the close-button, i want to display the property "Number" that dynamically changes during runtime!
http://geekswithblogs.net/kobush/archive/2007/04/08/closeabletabitem.aspx
If we have this class:
public class MyItem : INotifyPropertyChanged
{
public string Title {get; set;}
private int number;
public int Number
{
get { return number; }
set
{
number= value;
OnPropertyChanged("Number");
}
}
}
We can bind the collection of items to TabControl:
<TabControl ItemsSource="{Binding MyItems}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="{Binding Number}"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<my:TimeLine Number="{Binding Number, Mode=TwoWay}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>

WPF ListView SelectedValue not being set

I've looked at a few solutions but nothing has worked yet for me.
I'm using MVVM for this project and have a ListView that I can't set the SelectedItem property.
If this is my (simplified) XAML.
<ListView Name="uxPackageGroups" ItemsSource="{Binding Path=PackageGroups, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" BorderThickness="0"
BorderBrush="#FF0000E8" ScrollViewer.CanContentScroll="True"
SelectedItem="{Binding Path=PackageGroupSelectedItem, Mode=TwoWay}" >
<ListView.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Name}" Height="20" Margin="0" Padding="0"/>
</DataTemplate>
</ListView.ItemTemplate>
And I bind it to a PackageGroups in my ViewModel
public PackageGroup PackageGroupSelectedItem {get; set; }
public ObservableCollection<PackageGroup> PackageGroups {get; set; }
private void LoadUI()
{
PackageGroups = Factory.LoadAllPackageGroups())
// if I try to hard-code a pre-selected item here it doesn't work.
// 34 is a valid ID and I see a valid object when stepping through the code
PackageGroupSelectedItem = PackageGroup.LoadByID(db, 34);
}
Anything glaring in my code?
Thanks.
One possible problem is that you're not implementing INotifyPropertyChanged in the PackageGroupSelectedItem property.
I've just came into the same situation and it turned out that my collection item had incorrectly implemented "Equals" method. It doesn't need to implement INotifyPropertyChanged on collection item, but Equals should be implemented correctly...

WPF: ComboBoxes in ListBox and concurrency

I have code like this:
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock>Some Other Stuff Here</TextBlock>
<ComboBox ItemsSource="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The problem is, every time the outside ListBox.SelectedItem gets changed, the ComboBoxes inside it would change their SelectedIndex to -1. Which means if I click "Some Other Stuff Here" (unless the ListBoxItem it is in is selected), all the comboboxes' selection get cleared.
How do I overcome this? Thx!
Presumably your combobox is bound to something like an ObservableCollection - try exposing an instance of ICollectionView instead:
class DataSource
{
// ...
public ObservableCollection<string> MyData { get; private set; }
public ICollectionView MyDataView
{
get
{
return CollectionViewSource.GetDefaultView(this.MyData);
}
}
}
You can then bind your combobox with:
<ComboBox ItemsSource="{Binding MyDataView}" IsSynchronizedWithCurrentItem="True" />
This means that the 'selected item' for each data source is stored in the ICollectionView object instead of within the combobox, which should mean that it is persisted when the ListBox SelectedItem changes

Resources