更新
少し調査した後。問題のように思われるのは、Itemソースの読み込みが完了する前にSelectedValue/SelectedItemが発生していることです。ブレークポイントに座って数秒待つと、期待どおりに機能します。これをどのように回避するかわかりません。
更新の終了
MVVMとComboBoxを使用してWPFで使用するアプリケーションがあります。以下は、ViewModelの例です。私が抱えている問題は、ページを離れてComboBoxに戻るときに、現在選択されている値が選択されていないことです。
モデルの表示
public class MyViewModel
{
private MyObject _selectedObject;
private Collection<Object2> _objects;
private IModel _model;
public MyViewModel(IModel model)
{
_model = model;
_objects = _model.GetObjects();
}
public Collection<MyObject> Objects
{
get
{
return _objects;
}
private set
{
_objects = value;
}
}
public MyObject SelectedObject
{
get
{
return _selectedObject;
}
set
{
_selectedObject = value;
}
}
}
この例のために、MyObjectには2つのプロパティ(TextとId)があるとしましょう。 ComboBoxのXAMLは次のようになります。
XAML
<ComboBox Name="MyComboBox" Height="23" Width="auto"
SelectedItem="{Binding Path=SelectedObject,Mode=TwoWay}"
ItemsSource="{Binding Objects}"
DisplayMemberPath="Text"
SelectedValuePath="Id">
どの方法でページに戻ってオブジェクトを再構築するときにこれを構成しても、ComboBoxは値を選択しません。ただし、オブジェクトはプロパティのgetを介して正しいオブジェクトを返します。
これがComboBoxとMVVMパターンの動作の問題に過ぎないかどうかはわかりません。行っているテキストボックスバインドは正しく機能します。
ビューモデルにINotifyPropertyChanged
を実装して、PropertyChanged
が設定されたときにSelectedItem
イベントを発生させましたか?
これで問題が解決しない場合は、ページに戻るときに手動でPropertyChanged
イベントを発生させることができます。これで、WPFが自分自身を再描画して正しい選択を表示するのに十分なはずです項目。
設定IsSynchronizedWithCurrentItem="True"
私のために働いた!
SelectedItemプロパティの前にItemsSourceプロパティを配置する必要があります。数日前にこの問題について言及しているブログに出会いました。
この場合、オブジェクトのハッシュIDが異なるため、selecteditemバインドは機能しません。
1つの可能な解決策は次のとおりです。
選択されたアイテムIDに基づいて、itemsourceコレクションのオブジェクトを復元し、選択されたアイテムプロパティをそれに設定します。
例:
<ctrls:ComboBoxControlBase SelectedItem="{Binding Path=SelectedProfile, Mode=TwoWay}" ItemsSource="{Binding Path=Profiles, Mode=OneWay}" IsEditable="False" DisplayMemberPath="Name" />
ItemSourceにバインドされるプロパティは次のとおりです。
public ObservableCollection<Profile> Profiles
{
get { return this.profiles; }
private set { profiles = value; RaisePropertyChanged("Profiles"); }
}
SelectedItemにバインドされるプロパティは次のとおりです。
public Profile SelectedProfile
{
get { return selectedProfile; }
set
{
if (this.SelectedUser != null)
{
this.SelectedUser.Profile = value;
RaisePropertyChanged("SelectedProfile");
}
}
}
回復コードは次のとおりです。
[Command("SelectionChanged")]
public void SelectionChanged(User selectedUser)
{
if (selectedUser != null)
{
if (selectedUser is User)
{
if (selectedUser.Profile != null)
{
this.SelectedUser = selectedUser;
this.selectedProfile = this.Profiles.Where(p => p.Id == this.SelectedUser.Profile.Id).FirstOrDefault();
MessageBroker.Instance.NotifyColleagues("ShowItemDetails");
}
}
}
}
それがあなたのお役に立てば幸いです。答えを探すのに多くの時間を費やしましたが、見つけることができませんでした。
現在のページを離れると、CollectionView
のItemsSource
プロパティに関連付けられているComboBox
が削除されます。 ComboBox
IsSyncronizedWithCurrent
プロパティはデフォルトでtrueであるため、SelectedItem
およびSelectedValue
プロパティはリセットされます。
これは、バインディングの内部データ型の問題のようです。上記で他の人が提案したように、ビューモデルのintプロパティにバインドする代わりにSelectedValue
を使用すると、動作します。ショートカットは、MyObjectのEquals
演算子をオーバーライドして、2つのMyObjectを比較するときに実際のId
プロパティが比較されるようにすることです。
別のヒント:ビューモデルを再構築してSelectedValue
を使用する場合は、SelectedValuePath=Id
ここで、Id
はint
です。文字列キーを使用する場合は、Text
の代わりにComboBox
のSelectedValue
プロパティにバインドします。
以前にもこの動作に気づきました。 SelectedIndexプロパティが同じバグを引き起こさないことに気付きました。 ViewModelを再構築して、選択したアイテムのインデックスを公開し、それにバインドできる場合は、準備ができているはずです。
同じ問題がありました。事はです。選択したアイテムは、コレクションからどのオブジェクトを使用する必要があるかを知りません。そのため、コレクションのアイテムを使用するには、選択したアイテムに発言する必要があります。
public MyObject SelectedObject
{
get
{
Objects.find(x => x.id == _selectedObject.id)
return _selectedObject;
}
set
{
_selectedObject = value;
}
}
これがお役に立てば幸いです。
この問題に対する非常に簡単な答えがあります。最初に、次のコードをビューIsSynchronizedWithCurrentItem = "True"に追加します。
次に、ViewModelの新しいオブジェクトをそのプロパティに割り当てるときはいつでも、SelectedObjectはプライベートメンバーではなく、そのプロパティに保存する必要があります。
ビューモデルプロパティは次のようになります。
public Role SelectedObject
{
get { return object; }
set
{
if (value != null)
{
if (!object.Equals(value))
{
object = value;
OnPropertyChanged(() => SelectedObject );
}
}
}
}
これで問題が解決するはずです。
私はしばらくの間この問題と戦っていました。私の場合、アイテムソースとして複合型(リスト)を使用し、選択した値としてKeyTypeを使用していました。ロードイベントで、KeyTypeがnullに設定されていました。これにより、すべてが壊れました。キーが変更されても、サブ要素は更新されません。 KeyTypeの提案された値がnullでないことを確認するチェックを追加すると、すべてが期待どおりに機能することが判明しました。
#region Property: SelectedKey
// s.Append(string.Format("SelectedKey : {0} " + Environment.NewLine, SelectedKey.ToString()));
private KeyType _SelectedKey = new KeyType();
public KeyType SelectedKey
{
get { return _SelectedKey; }
set
{
if(value != null )
if (!_SelectedKey.Equals(value))
{
_SelectedKey = value;
OnPropertyChanged("SelectedKey");
}
}
}
#endregion SelectedKey
UserControl_Loadedイベントにディスパッチャを追加することで問題を解決しました
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
{
combobox.SelectedIndex = 0;
}));
SelectedValuePath
とSelectedValue
の型は完全に同じでなければなりません。
たとえば、SelectedValuePath
のタイプがInt16
およびSelectedValue
にバインドするプロパティのタイプはint
であり、機能しません。
私はそれを見つけるのに何時間も費やします、そしてそれは私が質問が尋ねられた多くの時間後にここで答えている理由です。同じ問題を抱えている私のような他の貧しい人がそれを見ることができるかもしれません。
色のリストを表示するComboBoxでこの問題が発生しました(List <Brush>)。
色の選択は可能でしたが、選択が閉じられたときに表示されませんでした(ただし、プロパティは変更されました!)
修正は、ComboBox(ブラシ)で選択されたタイプのEquals(object obj)メソッドを上書きしていました。だから私はクラスを書いた EqualityBrush Brushを含み、Equalsを実装します:
public class EqualityBrush
{
public SolidColorBrush Brush { get; set; }
public override bool Equals(object o)
{
if (o is EqualityBrush)
{
SolidColorBrush b = ((EqualityBrush)o).Brush;
return b.Color.R == this.Brush.Color.R && b.Color.G == this.Brush.Color.G && b.Color.B == this.Brush.Color.B;
}
else
return false;
}
}
通常のBrushクラスの代わりに新しいEqualityBrushクラスのリストを使用すると、問題が修正されました。
私のコンボボックス XAML 次のようになります。
<ComboBox ItemsSource="{Binding BuerkertBrushes}" SelectedItem="{Binding Brush, Mode=TwoWay}" Width="40">
<ComboBox.Resources>
<DataTemplate DataType="{x:Type tree:EqualityBrush}">
<Rectangle Width="20" Height="12" Fill="{Binding Brush}"/>
</DataTemplate>
</ComboBox.Resources>
</ComboBox>
私の「ブラシ」プロパティが ViewModel タイプEqualityBrushでなければなりません!
Loadedイベントを使用:
private void cmb_Loaded(object sender, RoutedEventArgs e) {
if (cmb.Items.Count > 0) cmb.SelectedIndex = 0;
}
わたしにはできる。
IsSyncronizedWithCurrent = Falseが機能します。
DataContextをページに適用する方法である可能性があります。 WPFでは、ページに移動するたびに、すべてが再初期化され、コンストラクターが呼び出され、メソッドが読み込まれます。したがって、ビュー内でDataContextを設定している場合、ユーザーが選択したSelectedItemを吹き飛ばすことは間違いありません。それを回避するには、ページのKeepAliveプロパティを使用します。
<Page KeepAlive="True" ...>
...
</Page>
これにより、既にアクセスしたページに戻るときにLoadedイベントのみが発生します。そのため、Loadではなく、Initialize(外部またはコンストラクター内)でDataContextを設定していることを確認する必要があります。
ただし、これはページのそのインスタンスに対してのみ機能します。そのページの新しいインスタンスに移動すると、コンストラクタが再度呼び出されます。
ComboBox.SelectionBoxItem.ToString()