0

In my application I have items which can contain a Town. Each Town consists of a PostalCode and a Name, e.g.

<Code>
  <Row
    Code="1234"
    Name="County A - Town A"
  />
</Code>
<Code>
  <Row
    Code="1234"
    Name="County A - Town B"
  />
</Code>
<Code>
  <Row
    Code="1235"
    Name="County B"
  />
</Code>
<Code>
  <Row
    Code="1236"
    Name="County C"
  />
</Code>

The PostalCode can be repeated for several towns.

In my UI I show the selection as follows: enter image description here

But this is confusing for the user, as there are multiple similar PostalCodes.

Is there a way to group the Towns by each distinct PostalCode and filter the second ComboBox with the filtered Names?

An important remark is that a Town is a property of an Item, which is my ListView's ItemsSource.

Edit

I've changed my code as suggested to the following:

XAML

    <ComboBox x:Name="PostalCodeComboBox"
        ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}, Path=DataContext.DistinctPostalCodeTowns}"
        SelectedItem="{Binding Address.Town}" SelectionChanged="PostalCodeComboBox_SelectionChanged" />

    <ComboBox x:Name="NameComboBox"
        ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}, Path=DataContext.TownsByCode}"
        SelectedItem="{Binding Address.Town}" SelectionChanged="NameComboBox_SelectionChanged" />

ViewModel

    public MainWindowViewModel()
    {
        VivendaContext = new DataModels.VivendaContext();
        //Call a ToList to load the data into the .Local property.
        VivendaContext.Premises.ToList();
        Premises = VivendaContext.Premises.Local;
        Towns = VivendaContext.Towns.ToList();
        //http://stackoverflow.com/a/1300116/1653998
        DistinctPostalCodeTowns = VivendaContext.Towns.DistinctBy(t => t.PostalCode).ToList();
        TownsByCode = Towns;
    }

    internal void PostalCodeComboBox_SelectionChanged(ComboBox sender)
    {
        if(sender.SelectedItem as Town != null)
        {
            TownsByCode = Towns.Where(t => t.PostalCode == (sender.SelectedItem as Town).PostalCode).ToList();
        } else
        {
            TownsByCode = Towns;
        }
    }

And this works wonderfully when I select a PostalCode, it filters the towns with that postalcode. But when I load my data (or select a Town via its Name), I only get to see a PostalCode when it's the first town with that postalcode.

I know this is a side-effect of the DistinctBy and the fact that not all Town Entities are available in my DistinctPostalCodeTowns property.

My first thought was to use the SelectionChanged event on my NameComboBox, to select the right Town via its postalcode, but as the PostalCodeComboBox is repeated for each item, I can't access it.

Any suggestions on how to get my PostalCodeComboBox selecting the right PostalCode as well?

Community
  • 1
  • 1
Benjamin Diele
  • 1,177
  • 1
  • 10
  • 26

2 Answers2

1

You have to define two collections. First will contain distinct codes and the second will dynamically fill Towns by code for every SelectionChanged event int Codes-listbox.

public string CurrentCode {get;set;}
public List<string> AllCodes {get;set;}
public List<Town> TownsByCode {get {return AllTowns.Where(r=>Code == CurrentCode).ToList();}}
public List<Town> AllTowns {get;set;}

XAML

// Codes selector
<ListBox SelectedItem="{Binding CurrentCode, Mode=TwoWay}" ItemsSource="Binding AllCodes">
</ListBox>

// Towns by code
<ListBox ItemsSource="Binding TownsByCode" />

Also in CurrentCode setter you must notify that TownsByCode property is changed.

opewix
  • 4,993
  • 1
  • 20
  • 42
  • Where do I define these extra properties? On my viewmodel? On my entity that contains a `Town`? Wont the second combobox still be filtered when I select a different item and want to change the town of that new item? – Benjamin Diele Dec 24 '14 at 19:40
  • These properties should be defined in ViewModel. When you select a different code, tows list be changed. – opewix Dec 24 '14 at 19:42
  • How can I use `CurrentCode` for each item? Suppose I have a list of 5 items, each with a different `PostalCode`? – Benjamin Diele Dec 24 '14 at 19:51
  • List of codes will contain 5 entries. `CurrentCode` will represent only one code which is selected in the list. Care, if nothing is selected, `CurrentCode` can be null. – opewix Dec 24 '14 at 19:54
  • I've edited my question with your suggestions. Would you care to look at it again? – Benjamin Diele Dec 25 '14 at 13:57
  • When make assign `TownsByCode = [...]` you must notify that property `TownsByCode` was changed. – opewix Dec 25 '14 at 17:44
  • That happens. I think my record is not selected because the `DistinctBy` yields the first `Town` with that `PostalCode`, and the currently selected `Town` is not the same record, but only has the same `PostalCode`. – Benjamin Diele Dec 25 '14 at 20:59
  • You should bind `SelectedItem` of `PostalCodeComboBox` to a separate variable `public string CurrentCode {get;set;}` – opewix Dec 26 '14 at 03:14
0

first if you want to define the name in XAML you should define it by this way :

<ComboBox Name="combo" HorizontalAlignment="Left" Margin="319,78,0,0" VerticalAlignment="Top" Width="120"/>

and you can edit it in C# code by this way:

combo.Items.Add("Hello");
combo.Items.Add("Combo");
combo.Items.Add("Box");

But if you want to write the whole code in C# :

ComboBox combo2 = new ComboBox();
combo2.Items.Add("I`m");
combo2.Items.Add("Mohamed");
combo2.Items.Add("Slama :p");
combo2.Margin = new Thickness(50, 50, 0, 0);
combo2.Foreground = new SolidColorBrush(Colors.Red);
      //add to canvas
canv.Children.Add(combo2);

I hope it will be useful

Mohamed Slama
  • 189
  • 1
  • 3
  • 17