C# 数据绑定到不同用户控件中的ObservableCollection-如何保留当前选择?
问题范围于2010年3月25日扩大 我最终解决了我的问题,但由于解决了原来的问题,出现了一个新问题,因为我希望能够将奖金奖励给某人 一旦我解决了我的问题,我很快发现,当ObservableCollection更新时,databound组合框的内容被重新填充,但大多数选择都被删除了 我假设在这种情况下,MVVM将使我难以记住最后选择的项目。我有个主意,但似乎有点恶心。我会把赏金奖励给任何能想出好办法的人 2010年3月24日重新编写的问题 我有两个UserControls,其中一个是一个有TabControl的对话框,另一个是出现在所述TabControl中的对话框。为了简单起见,我将它们命名为CandyDialog和CandyNameViewer。还有一个名为Tracker的数据管理类,它管理信息存储,无论出于何种目的,它只公开一个公共属性,即一个可观察的集合 我通过代码隐藏在CandyDialog中显示CandyNameViewer,如下所示:C# 数据绑定到不同用户控件中的ObservableCollection-如何保留当前选择?,c#,wpf,data-binding,mvvm,observablecollection,C#,Wpf,Data Binding,Mvvm,Observablecollection,问题范围于2010年3月25日扩大 我最终解决了我的问题,但由于解决了原来的问题,出现了一个新问题,因为我希望能够将奖金奖励给某人 一旦我解决了我的问题,我很快发现,当ObservableCollection更新时,databound组合框的内容被重新填充,但大多数选择都被删除了 我假设在这种情况下,MVVM将使我难以记住最后选择的项目。我有个主意,但似乎有点恶心。我会把赏金奖励给任何能想出好办法的人 2010年3月24日重新编写的问题 我有两个UserControls,其中一个是一个有TabC
private void CandyDialog_Loaded( object sender, RoutedEventArgs e)
{
_candyviewer = new CandyViewer();
_candyviewer.DataContext = _tracker;
candy_tab.Content = _candyviewer;
}
public SomeClass : DependencyObject
{
static DependencyPropertySynchronizer sync =
new DependencyPropertySynchronizer
{
Priority = DispatcherPriority.ApplicationIdle
};
public static readonly DependencyProperty HappinessProperty =
sync.RegisterAttached("Happiness", typeof(int), typeof(SomeClass));
public static readonly DependencyProperty JoyProperty =
sync.RegisterAttached("Joy", typeof(int), typeof(SomeClass));
}
CandyViewer的XAML如下所示(为kaxaml编辑):
现在,当加载控件时,一切正常。只要先填充CandyNames,,然后显示consumer UserControl,所有的名称都在那里。很明显,我没有在输出窗口中得到任何错误或类似的东西
我遇到的问题是,当从模型中修改ObservableCollection时,这些更改不会反映在consumer UserControl中!我以前从未遇到过这个问题;我以前对ObservableCollection的所有使用都得到了很好的更新,尽管在这些情况下,我没有跨程序集进行数据绑定。虽然我目前只在ObservaleCollection中添加和删除糖果名称,但稍后我可能还会允许从模型端重命名
我做错什么了吗?有没有一个很好的方法来调试它?用户间控制数据绑定是可能的。不幸的是,我的最爱并没有提出任何我可以用来解决这个特殊问题的建议。听起来你在ObservableCollection中的对象不想显示更改(或者ObservableCollection不想更改???),如果首先,我会在我的对象模型中使用INotifyPropertyChanged接口。我不是Bea Stolnitz(遗憾的是,她太棒了),但我想知道是否有可能通过在XAML中表达数据绑定关系的奥秘(在我看来,这一点都不可怕)combobox正在丢失其绑定到的属性实际上是ObservableCollection这一事实。您可能希望尝试从数据模型或combobox可以直接绑定到的其他层(而不是通过tab控件)公开ObservableCollection.您可能需要使用一点C#来实现这一点,而不是XAML,这可能会冒犯一些MVVM纯粹主义者,但我花了很多时间和时间来解决此类问题,这让我对XAML和MVVM有点反感。在我看来,如果我不能在一个小时左右的时间内让复杂的数据绑定场景正常工作,可能会是时候尝试另一种方法了。您的xaml让我困惑,但我认为您需要像这样绑定文本框:
{Binding SelectedCandy.CandyName}
当项目被添加或删除时,ObservableCollection会告诉WPF,因此如果从模型中删除或添加CandyNames,您应该会看到相应的组合框更新。但是如果更改CandyName,WPF要求您实现INotifyPropertyChanged,以便为WPF绑定提供一个提示
所以这很简单(如果我理解你的模型)
好吧,现在我觉得自己很愚蠢。我的代码考虑得很糟糕,直到今天我才发现我做错了什么。我已经将DataContext设置了两次,每一次都设置为一个不同的对象,不管出于什么原因,其中一个将CandyNames定义为列表!!!啊
我认为在UML中绘制绑定和关系图是值得的,这样就可以很容易地跟踪这些东西。MVVM+数据绑定有时肯定会让人困惑。当组合框的数据上下文发生变化时,我也遇到过同样的问题。我有一个相对简单的解决方案,它使用了我编写的一个名为“ComboBoxFixer”。一旦实现,您只需更换以下部件即可解决此问题:
<ComboBox ItemsSource="..." SelectedItem="..." />
通常是这样使用的:
private void CandyDialog_Loaded( object sender, RoutedEventArgs e)
{
_candyviewer = new CandyViewer();
_candyviewer.DataContext = _tracker;
candy_tab.Content = _candyviewer;
}
public SomeClass : DependencyObject
{
static DependencyPropertySynchronizer sync =
new DependencyPropertySynchronizer
{
Priority = DispatcherPriority.ApplicationIdle
};
public static readonly DependencyProperty HappinessProperty =
sync.RegisterAttached("Happiness", typeof(int), typeof(SomeClass));
public static readonly DependencyProperty JoyProperty =
sync.RegisterAttached("Joy", typeof(int), typeof(SomeClass));
}
上面的代码将使任何给定对象的附加Happiness和Joy属性保持同步:每当设置Happiness或Joy时,另一个将设置为DispatcherPriority.ApplicationIdle。DependencyPropertySynchronizer使用一个隐藏的附加属性实现,该属性存储在任一属性上设置的最后一个值和协调更新的计划。您还可以通过设置AutoSyncProperty与现有属性同步
使用这个类,我的ComboBoxFixer类非常简单:
public class ComboBoxFixer : DependencyObject
{
static DependencyPropertySynchronizer sync =
new DependencyPropertySynchronizer
{
Priority = DispatcherPriority.ApplicationIdle,
AutoSyncProperty = Selector.SelectedItemProperty,
};
public static readonly DependencyProperty SelectedItemProperty =
sync.RegisterAttached("SelectedItem", typeof(object), typeof(ComboBoxFixer),
new FrameworkPropertyMetadata
{
BindsTwoWayByDefault = true,
});
public static object GetSelectedItem(... // normal attached property stuff
public static void SetSelectedItem(...
}
它的工作原理
无论何时my:ComboBoxFixer.SelectedItem发生更改,同步器都会以ApplicationIdle优先级更新Selector.SelectedItem,反之亦然
数据流是:
ViewModel property
<- bound from ->
my:ComboBoxFixer.SelectedItem
<- synced with ->
ComboBox.SelectedItem
ViewModel属性
my:ComboBoxFixer.SelectedItem
ComboBox.SelectedItem
附加说明
在某些情况下,如果您实际上是switc
public class ComboBoxFixer : DependencyObject
{
static DependencyPropertySynchronizer sync =
new DependencyPropertySynchronizer
{
Priority = DispatcherPriority.ApplicationIdle,
AutoSyncProperty = Selector.SelectedItemProperty,
};
public static readonly DependencyProperty SelectedItemProperty =
sync.RegisterAttached("SelectedItem", typeof(object), typeof(ComboBoxFixer),
new FrameworkPropertyMetadata
{
BindsTwoWayByDefault = true,
});
public static object GetSelectedItem(... // normal attached property stuff
public static void SetSelectedItem(...
}
ViewModel property
<- bound from ->
my:ComboBoxFixer.SelectedItem
<- synced with ->
ComboBox.SelectedItem