1

I am working on radiobuttons and combobox in my wpf App. Although I am a C++ developer, I recently moved to C#. My app deals with dynamic generation of the above mentioned components. Basically I have created 4 dynamic radiobuttons in my app and on clicking each, i should should add different items to my combobox. Here is the code:

XAML:

<ItemsControl ItemsSource="{Binding Children}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Vertical" >
                        <RadioButton Content="{Binding RadioBase}"  Margin="0,10,0,0"  IsChecked="{Binding BaseCheck}" GroupName="SlotGroup"  Height="15" Width="80" HorizontalAlignment="Center" VerticalAlignment="Center"/>                            
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

<ComboBox Visibility="{Binding IsRegisterItemsVisible}" ItemsSource="{Binding RegComboList}" SelectedItem="{Binding SelectedRegComboList, Mode=TwoWay}" SelectedIndex="0" />

FPGARadioWidgetViewModel Class:

public ObservableCollection<FPGAViewModel> Children { get; set; }

    public FPGARadioWidgetViewModel()
    {
        Children = new ObservableCollection<FPGAViewModel>();
        Children.Add(new FPGAViewModel() { RadioBase = "Base 0x0", ID = 0 });
        Children.Add(new FPGAViewModel() { RadioBase = "Base 0x40", ID = 1 });
        Children.Add(new FPGAViewModel() { RadioBase = "Base 0x80", ID = 2 });
        Children.Add(new FPGAViewModel() { RadioBase = "Base 0xc0", ID = 3 });            
    }

FPGAViewModel Class:

private bool sBaseCheck;
    public bool BaseCheck
    {
        get { return this.sBaseCheck; }
        set
        {
            this.sBaseCheck = value;                
            AddComboItems();
            this.OnPropertyChanged("BaseCheck");
        }
    }    

private ObservableCollection<string> _RegComboList;
    public ObservableCollection<string> RegComboList
    {
        get { return _RegComboList; }
        set
        {
            _RegComboList = value;
            OnPropertyChanged("RegComboList");
        }
    }        

private void AddComboItems()
    {
        int baseRegister = 0x40 * ID;
        ObservableCollection<string> combo = new ObservableCollection<string>();            

        for (int i = 0; i < 0x40; i++)
        {
            int reg = (i * 8) + baseRegister;
            combo[i] = "0x" + reg.ToString("X");
        }

        RegComboList = new ObservableCollection<String>(combo);
        OnPropertyChanged("RegComboList");
    }


private bool isRegisterItemsVisible = false;
    public bool IsRegisterItemsVisible
    {
        get { return isRegisterItemsVisible; }
        set
        {
            isRegisterItemsVisible = value;
            OnPropertyChanged("IsRegisterItemsVisible");                
            OnPropertyChanged("RegComboList");
        }
    }

If you notice, on clicking a particular radiobutton, it should add items with different value in combobox based on ID. It has to be made sure that on clicking any radiobutton only the items of that should be added and previous content of combobox should be cleared. I am trying to do the same thing using my above code but nothing seems to appear in combobox when i debug.

Please help :)

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
Steven Wilson
  • 139
  • 1
  • 9
  • You say they are in separate view models? How are you assigning the DataContext? Are they both in the same view? -- If so it looks like you arn't binding ItemsSource correctly. – Alex Curtis Nov 03 '12 at 10:57
  • @AlexCurtis:DataContext is bound to `FPGARadioWidgetViewModel` class. There are 2 classes one FPGARadioWidgetViewModel and other FPGAViewModel :) – Steven Wilson Nov 03 '12 at 10:58
  • 2
    How does it know which childs RegComboList to bind with? You might need to have a SelectedFPGAViewModel.RegComboList binding in FPGARadioWidgetViewModel – Alex Curtis Nov 03 '12 at 11:02
  • @AlexCurtis: Well I am confused. Could you elaborate more on it please. A sample code would be great :) – Steven Wilson Nov 03 '12 at 11:04

2 Answers2

2

I would associate the ItemsSource of your ComboBox with the selected RadioButton. From your existing model I would make every FPGAViewModel have an ObservableCollection<string> which you have done. Then, as Alex Curtis said, you would create a binding between the selected radio button and the combo box's ItemsSource.

Have a look at this post, it is probably easier to get the selected radio button by changing your ItemsControl to use a ListBox with the existing DataTemplate. You can then bind the IsChecked property to the ListBoxItem.IsSelected.

           <ListBox ItemsSource="{Binding Children}" SelectedItem="{Binding YourSelectedItem}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Vertical" >
                            <RadioButton Content="{Binding RadioBase}"  Margin="0,10,0,0"  GroupName="SlotGroup"  Height="15" Width="80" HorizontalAlignment="Center" VerticalAlignment="Center">
                                <RadioButton.IsChecked>
                                    <Binding Path="IsSelected"
                                     RelativeSource="{RelativeSource AncestorType=ListBoxItem}" Mode="TwoWay" />
                                </RadioButton.IsChecked>
                            </RadioButton>                            
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>


<ComboBox Visibility="{Binding YourSelectedItem.IsRegisterItemsVisible}" ItemsSource="{Binding YourSelectedItem.RegComboList}" SelectedItem="{Binding YourSelectedItem.SelectedRegComboList, Mode=TwoWay}" SelectedIndex="0" />

Then in the ViewModel that contains the Children collection you need to have a:

    private FPGAViewModel _yourSelectedItem;

    public FPGAViewModel YourSelectedItem
    {
        get { return _yourSelectedItem; }
        set { _yourSelectedItem = value;
        OnPropertyChanged("YourSelectedItem");}
    }

To populate your items I would change the constructor of FPGAViewModel to accept the Base and ID as parameters so you can call AddComboItems() in the constructor.

public FPGAViewModel(string radioBase, int id)
{
    RadioBase = radioBase;
    ID = id;
    AddComboItems();
}

Now

Children.Add(new FPGAViewModel() { RadioBase = "Base 0x0", ID = 0 });

should become

Children.Add(new FPGAViewModel("Base 0x0", 0));
Community
  • 1
  • 1
nickm
  • 1,775
  • 1
  • 12
  • 14
  • Does `AddComboItems()` need to be triggered every time? Can't you call it once on initialisation of `FPGAViewModel`? – nickm Nov 05 '12 at 04:44
  • It should get triggered everytime the radiobutton is clicked. Since 4 radiobuttons are present, on each click, different items will get added to the combo. – Steven Wilson Nov 05 '12 at 04:45
  • Yeah that will happen if you populate each `RegComboList` once. Unless you need the contents of each `RegComboList` to change everytime you select a different radio button there is no need to repopulate the list. – nickm Nov 05 '12 at 04:50
  • In HTML I'd do this using four combo-boxes, only one of which is VISIBLE at a time, depending on which radio button is checked... I don't know if that approach would translate NICELY to WPF, because I'm still a WPF novice myself. – corlettk Nov 05 '12 at 04:50
  • @nmaait: throws an exception. Invocation of constructor. When i comment the constructor, Application works....... – Steven Wilson Nov 05 '12 at 05:09
  • Error seems to be coming from `combo[i] = "0x" + reg.ToString("X");`. Index out of range exception. – nickm Nov 05 '12 at 05:27
  • Change it to `combo.Add("0x" + reg.ToString("X"));` – nickm Nov 05 '12 at 05:30
  • @nmaait: Well it does inserts the value but its not showing in combobox. I put a breakpoint and I can c combo having items. But on Ui they aint getting displayed – Steven Wilson Nov 05 '12 at 05:42
  • Working for me, do you have the OnPropertyChanged("YourSelectedItem") set correctly? – nickm Nov 05 '12 at 05:57
  • @nmaait: u mean `OnPropertyChanged("RegComboList");`? – Steven Wilson Nov 05 '12 at 06:03
  • Yeah that too. But the property in my example need to raise the property changed event also. So the property in FPGARadioWidgetViewModel which is bound to the Listbox.SelectedItem. – nickm Nov 05 '12 at 06:05
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/19069/discussion-between-steven-wilson-and-nmaait) – Steven Wilson Nov 05 '12 at 06:06
1

That is because the combobox has been bound to a different reference of strings. Every radio click changes the items and returns a new reference to a list. Try reusing the current RegComboList by removing the existing items within it and then add the new ones. If that fails to update the combobox, make the binding to RegComboList two way.

Edit: Here is a working example .Net 4.5, don't worry the concepts are the same.

Here the combo box is loaded initially with 5 words. Then every time a user clicks the button, a new set of words is put into the list, changing the combo box. Note the clear done for the collection.

The picture is after the initial "Lorem Ipsum" load...

2nd Run where it is past the Lorem Ipsum

<Window x:Class="WPFCombo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50*" />
            <RowDefinition Height="50*" />
            <RowDefinition Height="172*" />
        </Grid.RowDefinitions>
        <Button Content="Button"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Width="75"
                Click="Button_Click_1" />
        <ComboBox HorizontalAlignment="Center"
                  Grid.Row="1"
                  ItemsSource="{Binding RegComboList}"
                  VerticalAlignment="Center"
                  Width="120" />
    </Grid>
</Window>

Code behind

public partial class MainWindow : Window,  INotifyPropertyChanged
{
    private const string cLorem = @"Lorem ipsum dolor sit amet consectetur adipiscing elit Maecenas
                                   et lacinia nisl Aenean nec aliquet risus Phasellus dui purus 
                                   sollicitudin nec cursus vitae cursus id purus Nam quis risus 
                                   velit Sed aliquam tellus in odio pulvinar tincidunt Sed bibendum mi";



    private int Skip { get; set; }
    private ObservableCollection<string> _RegComboList;
    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection<string> RegComboList
    {
        get { return _RegComboList; }
        set
        {
            _RegComboList = value;
            OnPropertyChanged();
        }
    }


    public MainWindow()
    {
        InitializeComponent();
        RegComboList = new ObservableCollection<string>();
        GenerateWords(5);

        DataContext = this;
    }

    private void GenerateWords(int toTake)
    {
        RegComboList.Clear();

        Regex.Split(cLorem, @"\s+").Skip(Skip)
             .Take(toTake)
             .ToList()
             .ForEach(word => RegComboList.Add( word ));

        Skip += toTake;

    }

    protected virtual void OnPropertyChanged( [CallerMemberName] string propertyName = "" )
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler( this, new PropertyChangedEventArgs( propertyName ) );
        }
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        GenerateWords(new Random().Next(1, 10));
    } 
}
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
  • Well I tried setting the two way mode but it throws an error here: `combo[i] = "0x" + reg.ToString("X");` as `Index was out of range. Must be non-negative and less than the size of the collection.` – Steven Wilson Nov 03 '12 at 11:15
  • @StevenWilson Why don't you try to load the box with dummy text, before trying the dynamic loading...that way you can determine where your problem actually lies... – ΩmegaMan Nov 03 '12 at 18:08