tags:

views:

827

answers:

9

I have overrided the method OnSourceInitialized and I have one problem. After populating my combobox with source property from c# code I want automatically an item will appear selected in the combobox when a page is loaded (default value) but for some reason after onsourceinitialized method, the combobox selected item change to null.

A: 

Set the SelectedIndex property at the end of your override, by the way, i can't seem to find OnSourceInitialised, only Initialised. But it should still work if you set it at the end of your code.

    private void MyListBox_Initialized(object sender, EventArgs e)
    {
        // Run some code
        if (MyListBox.Items.Count > 0)
        {
            MyListBox.SelectedIndex = 0;
        }
    }
LnDCobra
A: 

Hi! Sorry for not explaining it correctly. I have a class that inherits from Window and I override the OnSourceInitialized method for this window. Then in my constructor I add the events handlers:

Loaded += PreferencesWindow_Loaded; Closing += PreferencesWindow_Closing;

and after it I populate my combobox:

Loaded += PreferencesWindow_Loaded; Closing += PreferencesWindow_Closing;

InitializeComponent();

myCombo.ItemsSource = Accessor.GetLimHorasExtraSorted();

FillControls();

where Accessor is a class that contains the method that obtains data from a database and returns a table with columns: Id, LimHora.

in my xaml:

         <ComboBox x:Name="myCombo" DisplayMemberPath="LimHora"
           SelectedValuePath="Id"  SelectedItem="{Binding Path=Id}"
           VerticalAlignment="Center"  HorizontalContentAlignment="Right" Width="50">
          </ComboBox>                        

Once my combobox is populated, I select by default the one is currently in another table that contains the default values of my application. I do it by calling the FillControls() method above, which access to data base and obtain an object.Finally I do it:

MyCombo.Text = tbl_pref.LimHora.ToString();

All ok until here, but after OnSourceInitialized method executes, the selected value for my combo change to null and I don't know why. My window opens and in the combobox doesn't appear selected the default value I want.

Thanks very much.

toni
A: 

I don't have a real answer to your question, but OnSourceInitialized seems to be too early in the initialization process.

Again, I have not tried your exact scenario, but many problems like this one are solved by calling FillControls (i.e. setting the selected item) in the Loaded event instead of earlier.

Timores
A: 

Hi!

Thanks very much for your help. I have called FillControls() in diferent parts of my application but the problem follows.

I have tested it in constructor, in Loaded event, at the end of OnSourceInitialized, but don't work.

What is the best place to populate the combo and select a value by default from the combobox?

I have seen that when window opens the default value that I want to appear in the combobox is selected but very fast I disappears. Which method executes after OnSourceInitialized? I think there is another method after OnSourceInitialized that makes combobox selected value change to null but I don't know what method is.

Thanks.

toni
A: 

Anybody knows why combobox selectionChanged event is fired after executing overrided OnSourceInitialized method of my window? I don't change the value of the combobox! It causes selectedValue property of my combobox to get null value! and I don't want it. Is it a bug¿? I don't understand this behaviour.

Thanks in advance everybody.

toni
Don't post answers to your question, edit the question instead. It became completely undreadable by now.
Stanislav Kniazev
A: 

Cause

This appears to be the problem:

SelectedItem="{Binding Path=Id}" 

If the "Id" property in the DataContext is not an item in the ItemsSource, SelectedItem will be set to null.

Timing

When InitializeComponent is called, it parses the XAML which sets the SelectedItem binding. If the DataContext is not set, then initially this will be null. Later when DataContext is set, the binding is re-evaluated. If Id is in the list at that point, the SelectedItem is set. Otherwise it is set to null.

Any binding that cannot be evaluated initially during InitializeComponent is scheduled using the dispatcher to be re-evaluated once all events have fired. Without details on how your DataContext is being set I can't give specifics, but my guess is that one of your binding is getting deferred so your {Binding Path=Id} binding is evaluated in a dispatcher callback.

A dispatcher callback is not an event - it is a prioritized work queue. If you have this kind of situations your choices are:

  1. Change the bindings so they can be evaluated during initialization
  2. Use a Dispather.BeginInvoke to schedule your own callback to execute after the Binding completes
  3. Let the Binding take care of setting the SelectedItem rather than setting manually in code

Additional notes

Your use of SelectedValueSource looks suspicious. Your binding to SelectedItem seems to indicate that each item in the ItemsSource is an "Id", but your definition of SelectedValueSource seems to indicate that each item in the ItemsSource contains an "Id". It is rare to find a data structure where the structure itself is called "Id" by another structure, yet it itself has an "Id" field. Thus I suspect some confusion here. Without seeing your actual data structures I can't say more.

Your use of OnSourceInitialized also makes it appear you have a misunderstanding. The "Source" in the name of OnSourceInitialized refers to a "presentation source" such as a Win32 hWnd, not a source of data. The purpose of OnSourceInitialized is to interact at a low level with the Windows operating system, or to update your application based on where it is being presented. Your use seems completely unrelated to this. I would recommend you stay away from OnSourceInitialized. Generally the best time to initialize ComboBoxes and such is to just provide it in your view model and let data binding take care of it. As soon as the view model is available the data will be populated with no code required.

Ray Burns
A: 

Hi again,

First of all, very good explanation thanks.

I'll try to explain more and I post some code following. I have made some modifications but without success. It continues not working.

My goal is to show a default value selected in the combobox when window is loaded and it is shown.

Initially, when user selects a option in menu application I do the following:

WinMain.xaml.cs:

    namespace MyNamespace
    {

      public partial class WinMain : Window
      {

          <...>

          private void mnuItemPreferences_Click(object sender, RoutedEventArgs e)
          {

            MyNamespace.Windows.EditPreferences editPrefWnd = 
                   new MyNamesapece.Windows.EditPreferences();

            //
            // Modal window that I want to open with default values in comboboxes
            //
            editPrefWnd.ShowDialog();
          }

          <...>

        } // end WinMain class
      } // end namespace

EditPreferences.xaml.cs:

           namespace MyNamespace.Windows
           { 
              public partial class EditPreferences : Window
              {
                 <...>

                 // My constructor
                 public EditPreferences()
         {
                    //
                    // Handlers
                    //
                    Loaded += PreferencesWindow_Loaded;
                    Closing += PreferencesWindow_Closing;

        InitializeComponent();

        if (System.Environment.OSVersion.Version.Major < 6) 
                    {
            this.AllowsTransparency = true;
            _bolAeroGlassEnabled = false;
        }

        else 
                    {
            _bolAeroGlassEnabled = true;
        }

                    this.ShowInTaskbar = false;

                 } // end constructor

         private void PreferencesWindow_Loaded(object sender,
                                                     System.Windows.RoutedEventArgs e)
         {

                   if (this.ResizeMode != System.Windows.ResizeMode.NoResize)
                   {
                     //this work around is necessary when glass is enabled and the 
                     //window style is None which removes the chrome because the 
                     //resize mode MUST be set to CanResize or else glass won't display

                     this.MinHeight = this.ActualHeight;
                     this.MaxHeight = this.ActualHeight;

                     this.MinWidth = this.ActualWidth;
                     this.MaxWidth = this.ActualWidth;
                   }


                  //
                  // Populate comboboxes
                  //
                  cbLimHorasExtra.ItemsSource = Accessor.GetLimHorasExtraSorted();
                  cbFracHorasExtra.ItemsSource = Accessor.GetFracHorasExtraSorted();

                  //
                  // Fill controls with default values (see below)
                  //
                  FillControls();

                  //
                  // Install other handlers
                  //
                  rdoBtnOTE.Checked += this.rdoBtnOTE_Checked;
                  rdoBtnOTM.Checked += this.rdoBtnOTM_Checked;
                  chkboxRestrict.Checked += this.chkboxRestrict_Checked;
                  expAdditionalDetails.Collapsed += 
                                    this.expAdditionalDetails_Collapsed;
                  expAdditionalDetails.Expanded += this.expAdditionalDetails_Expanded;
                  cbLimHorasExtra.SelectionChanged += 
                       this.cbLimHorasExtra_SelectionChanged;
                  cbFracHorasExtra.SelectionChanged += 
                       this.cbFracHorasExtra_SelectionChanged;
                 }

                 protected override void OnSourceInitialized(System.EventArgs e)
                 {

                     base.OnSourceInitialized(e);

                     if (_bolAeroGlassEnabled == false)
                     {
                        //no aero glass
                        this.borderCustomDialog.Background =  
                              System.Windows.SystemColors.ActiveCaptionBrush;
                        this.tbCaption.Foreground = 
                              System.Windows.SystemColors.ActiveCaptionTextBrush;
                        this.borderCustomDialog.CornerRadius = 
                              new CornerRadius(10, 10, 0, 0);
                        this.borderCustomDialog.Padding = 
                              new Thickness(4, 0, 4, 4);
                        this.borderCustomDialog.BorderThickness = 
                              new Thickness(0, 0, 1, 1);
                        this.borderCustomDialog.BorderBrush =
                              System.Windows.Media.Brushes.Black;
                      }
                      else
                      {
                         //aero glass
                         if (VistaAeroAPI.ExtendGlassFrame(this, 
                                 new Thickness(0, 25, 0, 0)) == false)
                         {
                            //aero didn't work make window without glass
                            this.borderCustomDialog.Background = 
                                 System.Windows.SystemColors.ActiveCaptionBrush;
                            this.tbCaption.Foreground = 
                                 System.Windows.SystemColors.ActiveCaptionTextBrush;
                            this.borderCustomDialog.Padding = 
                                 new Thickness(4, 0, 4, 4);
                            this.borderCustomDialog.BorderThickness = 
                                 new Thickness(0, 0, 1, 1);
                            this.borderCustomDialog.BorderBrush = 
                                 System.Windows.Media.Brushes.Black;

                            _bolAeroGlassEnabled = false;
                         }
                       }
                 }

                 private void FillControls()
                 {
                     tblPreferencias tbl_pref = null;

                     //
                     // Obtain data (a record with fields)
                     // Accessor is a class where I define the methods to 
                     // obtain data of different tables in my database
                     //
                     tbl_pref = Accessor.GetActualPreferencias();

                     //
                     // Only returns one register
                     //
                     if (tbl_pref != null)
                     {
                        rdoBtnOTE.IsChecked = (bool)tbl_pref.OTE;
                        rdoBtnOTM.IsChecked = (bool)tbl_pref.OTM;
                        chkboxRestrict.IsChecked = 
                                              (bool)tbl_pref.RestriccionHExtraTipoA;

                        // Here the value assigned is always in the range of the values
                        // which combo has been populated. 
                        // With one 0 ... 8
                        // I debbugged it and works.
                        // selected value (no null) and text gets the correct value I 
                        // want but after OnSourceInitialized method is executed I note
                        // that for some rease selected value property gets value null
                        cbLimHorasExtra.Text = tbl_pref.LimiteHorasExtra.ToString();
                        cbFracHorasExtra.Text = 
                                         tbl_pref.FraccionDeMinutosExtra.ToString();
                     }
                 }

                 <...>
              } // end EditPreferences class
           } // end namespace

EditPreferences.xaml (I put as example one of the comboboxes):

            <Window x:Class="MyNamespace.Windows.EditPreferences"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Title="EditPreferences" Height="Auto" Width="500"
             Background="{x:Null}"
             SnapsToDevicePixels="True" SizeToContent="Height" 
             WindowStartupLocation="CenterScreen"
             ResizeMode="NoResize" 
             WindowStyle="None"
             Margin="0,0,0,0"  
             >

             <...>

             <ComboBox x:Name="cbLimHorasExtra" 
                       DisplayMemberPath="LimHora"
                       SelectedValuePath="Id"  
                       SelectedItem="{Binding Path=Id}"
                       VerticalAlignment="Center" 
                       HorizontalContentAlignment="Right"
                       Width="50"/>

             <...>
             </Window>

Accessor.cs:

             namespace GesHoras.Classes
             {

               class Accessor
               {
                <...>

                // This method is used to populate the combobox with its values
                // tblLimHorasExtra is a table in my SQL Database
                // Its fields are:
                //
                // Id : int no null (numbers 1 ... 9)
                // LimHora: int no null (numbers 0 ... 8)
                //
                public static System.Collections.IEnumerable GetLimHorasExtraSorted()
                {
                   DataClassesBBDDDataContext dc = new
                                                   DataClassesBBDDDataContext();

                   return (from l in dc.GetTable<tblLimHorasExtra>()
                           orderby l.LimHora
                           select new { Id=l.Id, LimHora=l.LimHora });
                }

               // tblPreferencias is a table in my SQL Database
               // Its fields are:
               //
               // Id : int no null
               // Descripcion : varchar(50) no null
               // OTE : bit no null
               // OTM : bit no null
               // LimiteHorasExtra : int no null
               // FraccionDeMinutosExtra : int no null
               // RestriccionHExtraTipoA : bit no null
               //
               public static tblPreferencias GetActualPreferencias()
               {
                    DataClassesBBDDDataContext dc = new
                                                    DataClassesBBDDDataContext();

                     return (from actP in dc.GetTable<tblPreferencias>()
                             where (actP.Id == 3)
                             select actP).SingleOrDefault<tblPreferencias>();
                }
                <...>

             } // end class
           } // end namespace

The problem I see is that when method fillControls is executed all is ok, selectedvalue and text property for the combobox is correct (I have debbugged it and is correct) but after executing OnSourceInitialized method, selectedvalue property for the combobox gets null value.

Also I note that, when window opens, the comboboxes appear with the default values selected that I want but quickly I see that for some reason their values selected turns to empty in the comboboxes. It's like some event (I think after executing OnSourceMethod because I have debugged and see how it change to null) makes the selected default values that appears ok in the comboboxes turn to empty.

I have tested that comboboxes are populated correctly because once the window is shown I click in the comboboxes and I can see they are populated ok.

Thanks.

toni
A: 

Also I have forced selected index for combobox in fillControls method by doing:

cbLimHorasExtra.SelectedIndex = 1;

but without success...

The combobox is populated with values: 0 to 8 both included.

toni
A: 

Hi, I have solved it!!!!!!

The problem was in binding the SelectedItem property in EditPreferences.xaml:

         <ComboBox x:Name="cbLimHorasExtra" 
                   DisplayMemberPath="LimHora"
                   SelectedValuePath="Id"  
                   SelectedItem="{Binding Path=Id}"
                   VerticalAlignment="Center" 
                   HorizontalContentAlignment="Right"
                   Width="50"/>

The solution is to change to:

         <ComboBox x:Name="cbLimHorasExtra" 
                   DisplayMemberPath="LimHora"
                   SelectedValuePath="Id"  
                   SelectedItem="Id"
                   VerticalAlignment="Center" 
                   HorizontalContentAlignment="Right"
                   Width="50"/>

Now it works perfectly ;)

Thanks very much.

toni