Depending Autocompleteboxes

Feb 25, 2011 at 7:43 AM

Hi

I have the following problem:

Say we have a customer workspace with two Autocompleteboxes called State and City. (Databinding to the state and city of the loaded customer address)

AutocompleteBox "State" is providing all the States of the US, while "City" provides the cities of the chosen state.

I only want to load the citites of this specific selected state each time when the selection changes, rather than loading all of the cities and filtering.

How is the easiest way to achieve this with Caliburn.Micro?

Thanks in advance

Feb 25, 2011 at 9:57 AM

Aside from Caliburn.Micro, it really depends on how you implemented your model (not view-model).

If you just have strings to represent states and cities, and you have a function that given a state returns the collection of its cities, can't you simply databind the cities AutoCompleteBox ItemsSource with the collection of state cities?

I'm afraid you need to provide more information if you need a better answer.

 

Feb 25, 2011 at 10:36 AM

I have a relational database (MS Sql Server):

State (1) <----> (*) City

It is mapped with EF4 and provided by a WCF Ria Service.

The Problem is, that I don't want to load the whole bunch of State/City data.(performance reason)

I only want to load the cities of the selected state. (lazy loading)

I am not very used with SL4 and Caliburn, so I think the performance is better this way, don't you think so?

If you can tell me a better, easier way with a nicer user experience, I am looking forward for new ideas.

Best regards

Feb 25, 2011 at 10:59 AM

What if you define the view model this way

public class ViewModel : Screen
{
         private string m_State;
         private string m_City;
         public BindableCollection Cities { get; private set; }
         public BindableCollection States { get; private set; }
         public string State
         {
             get { return m_State; }
             set
             {
                  if (m_State != value)
                  {
                      var oldValue = m_State;
                      m_State = value;
                      OnStateChanged(oldValue, value);
                      NotifyPropertyChanged(() => State);
                  }
         }

         public string City
         {
             get { return m_City; }
             set
             {
                  if (m_City!= value)
                  {
                      var oldValue= m_City;
                      m_City = value;
                      OnCityChanged(oldValue, value);
                      NotifyPropertyChanged(() => City);
                  }
             }
         }

         public ViewModel()
         {
              States = new BindableCollection();
              //Initialize the states collection...
              States.AddRange(GetStates());
              Cities = new BindableCollection();
         }

         private void OnStateChanged(string oldValue, string newValue)
         {
               //Apply the change to the model...
               Cities.Clear();
               //Retrieve the cities using your WCF service
               var cities = GetCities(newValue);
               Cities.AddRange(cities);
         }

         private void OnCityChanged(string oldValue, string newValue)
         {
               //Apply the change to the model...
               Cities.Clear();
         }
}

Cities are updated every time the currently selected state changes. Depending on your WCF service you could decide to implement cities loading using an IResult, and retrieve them in batches.

Given such view-model, you could bind the auto complete boxes sources to the corresponging bindable collection and the selected value to the auto complete box text.

 

Is this not enough? Have I misunderstood your question?

Feb 25, 2011 at 8:06 PM
Edited Feb 25, 2011 at 8:07 PM

Looks good. Thanks. I'm gonna check it out soon....

Feb 27, 2011 at 10:21 AM

Works perfectly thanks. The only problem still remains is clearing the text of the "City" Autocompletebox after changing the value of the "State" Autocompletebox. In the ViewModel, I clear the SelectedCity and the Cities (BindableCollection) after selecting a new state. What still remains in the City AutocompleteBox is the search text, that I typed in before. Because the SearchText property of the AutocompleteBox is read only, I cannot clear it from the ViewModel.

Feb 27, 2011 at 3:44 PM

I would use an attached behaviour over the AutoCompleteBox, in this case.

You can define a string property used to store the State value and, as soon as the value changes, reset the search text.

If I was not clear enough, I can provide a sample.

Feb 27, 2011 at 6:13 PM

Hi BladeWise

I'd be glad if you could post a sample. I don't know how to achieve that. The SearchText property of the ACB is readonly.

Thanks in advance

Feb 27, 2011 at 6:21 PM

Can you point me to the AutoCompleteBox implementation you are using?

If really there is really no method to clear the search text (even using code-behind), I fear that your only option is to customize the ABC.

Feb 28, 2011 at 5:48 PM
Edited Feb 28, 2011 at 5:50 PM

I am using the ACB of the latest SL4 class library.

http://msdn.microsoft.com/en-us/library/system.windows.controls.autocompletebox(v=vs.95).aspx

This is my State ACB:

<sdk:AutoCompleteBox
            Width="57"
            Height="23"
            Grid.Column="1"
            Grid.Row="5"
            HorizontalAlignment="Left"
            Margin="3"
            VerticalAlignment="Top"
            IsTextCompletionEnabled="True"
            FilterMode="StartsWith"
            ItemsSource="{Binding States}"
            SelectedItem="{Binding StatePrivate, Mode=TwoWay}"
            ValueMemberPath="Abbreviation">
            <sdk:AutoCompleteBox.TextBoxStyle>
               <Style TargetType="TextBox">
                  <Setter Property="MaxLength" Value="2"/>
               </Style>
            </sdk:AutoCompleteBox.TextBoxStyle>
                <sdk:AutoCompleteBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Abbreviation, Mode=TwoWay}"/>
                    </DataTemplate>
                </sdk:AutoCompleteBox.ItemTemplate>
            </sdk:AutoCompleteBox>
<sdk:AutoCompleteBox>

And the City ACB:

<sdk:AutoCompleteBox
            Width="196"
            Height="23"
            Grid.Column="1"
            Grid.Row="5"
            HorizontalAlignment="Left"
            Margin="65,3,3,3"
            VerticalAlignment="Top"
            FilterMode="Contains"
            IsTextCompletionEnabled="True"
            ItemsSource="{Binding Path=CitiesPrivate}"
            SelectedItem="{Binding CityPrivate, Mode=TwoWay}"
            ValueMemberPath="PostcodeWithCityName">
                <sdk:AutoCompleteBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding PostcodeWithCityName, Mode=TwoWay}"/>
                    </DataTemplate>
                </sdk:AutoCompleteBox.ItemTemplate>
</sdk:AutoCompleteBox>
 

Feb 28, 2011 at 5:55 PM
Edited Feb 28, 2011 at 5:56 PM

It's a little bit different because I'm binding to entities instead of strings. It works perfectly except the problem with the SearchText.

Kind regards. 

Feb 28, 2011 at 7:03 PM

Sorry for the silly question: have you tried with Text property? What does it control?

Mar 1, 2011 at 5:37 AM
Edited Mar 1, 2011 at 5:37 AM

Yes I have, but caused some problems in conjunction with binding to Entity Collections. There were some stupid entries in the drop down list of the ACB.

Maybe, I did something wrong. I am going to try it again.

Mar 1, 2011 at 4:17 PM

Yes it works. I just made a string property, bound it to the Text of the ACB and clear it after the State has changed. Never thought that I can use the text of the ACB just to clear the typed text.

Appreciate your help. Thanks.