我高估了OnSourceInitialized方法,我有一个问题。在使用c#代码中的源属性填充combobox之后,在加载页(默认值)时,将自动在组合框中显示选中的项,但由于某种原因,在进行onsourceinitialized方法之后,组合框选定的项将更改为null。
编辑
首先,非常好的解释谢谢。
我将尝试解释更多,并在下面发布一些代码。我做了一些修改,但没有成功。它继续不起作用。
我的目标是在加载窗口并显示时,在组合框中显示一个默认值。
最初,当用户在菜单应用程序中选择一个选项时,我执行以下操作:
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 (我举一个组合框为例):
<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
我看到的问题是,当方法fillControls被执行时,combobox的selectedvalue和text属性都是正确的(我已经对它进行了调试,并且是正确的),但是在执行OnSourceInitialized方法之后,combobox的selectedvalue属性将获得null值。
我还注意到,当窗口打开时,组合框会出现,并选择我想要的默认值,但我很快就会看到,由于某些原因,它们的值在组合框中变为空值。这类似于一些事件(我认为是在执行OnSourceMethod之后,因为我已经调试并查看了它如何更改为null),使在组合框中显示为ok的选定默认值变为空。
我已经测试了comboboxes的正确填充,因为一旦显示了窗口,我就在组合框中单击,我可以看到它们被填充了。
编辑2
此外,我还强制在fillControls方法中为combobox选择索引,方法如下:
cbLimHorasExtra.SelectedIndex = 1;
但没有成功..。
combobox中填充了值:0到8,两者都包括在内。
发布于 2010-03-01 18:17:19
致
这似乎就是问题所在:
SelectedItem="{Binding Path=Id}"
如果DataContext
中的"Id“属性不是ItemsSource中的项,则SelectedItem
将设置为null。
定时
当调用InitializeComponent
时,它解析设置SelectedItem
绑定的XAML。如果没有设置DataContext
,那么最初它将为null。稍后,当设置DataContext
时,重新计算绑定。如果此时Id
在列表中,则设置SelectedItem
。否则,它将设置为空。
任何在InitializeComponent
期间无法最初评估的绑定都会使用dispatcher进行调度,一旦所有事件触发,将重新评估这些绑定。如果没有关于如何设置DataContext的详细信息,我无法给出具体的内容,但我的猜测是,您的一个绑定正在被推迟,因此您的{Binding Path=Id}
绑定将在dispatcher回调中进行评估。
dispatcher回调不是一个事件-它是一个优先级工作队列。如果你有这种情况,你的选择是:
修改绑定,以便在initialization
中手动设置。
附加备注
你对SelectedValueSource
的使用看起来很可疑。绑定到SelectedItem
似乎表明ItemsSource
中的每一项都是"Id",但SelectedValueSource
的定义似乎表明ItemsSource
中的每一项都包含"Id“。很少能找到一个数据结构,其中结构本身被另一个结构称为"Id“,但是它本身有一个"Id”字段。因此,我怀疑这里有些混乱。没有看到您的实际数据结构,我不能说更多。
您对OnSourceInitialized
的使用也会使您看起来有一个误会。OnSourceInitialized
名称中的" source“指的是”表示源“,如Win32 hWnd,而不是数据源。OnSourceInitialized
的目的是与Windows操作系统进行低级别的交互,或者根据应用程序的出现位置更新应用程序。你的使用似乎与此完全无关。我建议你离OnSourceInitialized
远点。通常,初始化ComboBoxes的最佳时机就是在视图模型中提供它,并让数据绑定来处理它。一旦视图模型可用,数据将被填充,不需要任何代码。
发布于 2010-03-01 12:01:07
在覆盖结束时设置SelectedIndex属性,顺便说一句,我似乎找不到OnSourceInitialised,只是初始化了。但是,如果您在代码的末尾设置了它,那么它仍然可以工作。
private void MyListBox_Initialized(object sender, EventArgs e)
{
// Run some code
if (MyListBox.Items.Count > 0)
{
MyListBox.SelectedIndex = 0;
}
}
发布于 2010-03-01 13:56:59
对于您的问题,我没有一个真正的答案,但是OnSourceInitialized在初始化过程中似乎还为时过早。
同样,我还没有尝试过您的确切场景,但许多问题都是通过在加载事件中调用FillControls (即设置所选项)来解决的,而不是更早。
https://stackoverflow.com/questions/2355531
复制相似问题