gpt4 book ai didi

c# - 数据绑定(bind)到不同 UserControl 中的 ObservableCollection - 如何保留当前选择?

转载 作者:行者123 更新时间:2023-12-03 10:30:57 24 4
gpt4 key购买 nike

问题范围于 2010-03-25 扩大

我最终弄清楚了我的问题,但是由于解决了原始问题,所以出现了一个新问题,因为我希望能够将赏金奖励给某人!!!

一旦我发现了我的问题,我很快就发现当 ObservableCollection 更新时,数据绑定(bind)的 ComboBox 重新填充了它的内容,但大多数选择都被清除了。

我假设在这种情况下,MVVM 会让我难以记住最后选择的项目。我有一个想法,但它似乎有点讨厌。我会将赏金奖励给为此提出一个很好的解决方案的人!

问题重写于 2010-03-24

我有两个用户控件,其中一个是具有 TabControl 的对话框,另一个是出现在所述 TabControl 中的对话框。我就叫他们糖果对话 CandyNameViewer 为了简单起见。还有一个名为 的数据管理类。追踪器 它管理信息存储,出于所有意图和目的,它只公开一个公共(public)属性,即 ObservableCollection。

我通过后面的代码在 CandyDialog 中显示 CandyNameViewer,如下所示:

private void CandyDialog_Loaded( object sender, RoutedEventArgs e)
{
_candyviewer = new CandyViewer();
_candyviewer.DataContext = _tracker;
candy_tab.Content = _candyviewer;
}

CandyViewer 的 XAML 看起来像这样(为 kaxaml 编辑):
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<DataTemplate x:Key="CandyItemTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"></ColumnDefinition>
<ColumnDefinition Width="150"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding CandyName}" Margin="3"></TextBox>
<!-- just binding to DataContext ends up using InventoryItem as parent, so we need to get to the UserControl -->
<ComboBox Grid.Column="1" SelectedItem="{Binding SelectedCandy, Mode=TwoWay}" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.CandyNames}" Margin="3"></ComboBox>
</Grid>
</DataTemplate>
</Page.Resources>

<Grid>
<ListBox DockPanel.Dock="Top" ItemsSource="{Binding CandyBoxContents, Mode=TwoWay}" ItemTemplate="{StaticResource CandyItemTemplate}" />
</Grid>
</Page>

现在加载控件时一切正常。只要 CandyNames 被填充 第一个 ,然后显示消费者 UserControl,所有名称都在那里。我显然在输出窗口或类似的东西中没有任何错误。

我遇到的问题是,当从模型修改 ObservableCollection 时,这些更改是 不是 体现在消费者UserControl中!我以前从未遇到过这个问题;我以前对 ObservableCollection 的所有使用都更新得很好,尽管在那些情况下我没有跨程序集进行数据绑定(bind)。虽然我目前只在 ObservableCollection 中添加和删除糖果名称,但稍后我可能还会允许从模型端重命名。

是不是我做错了什么?有没有真正调试这个的好方法? Reed Copsey indicates here UserControl 间的数据绑定(bind)是可能的。不幸的是,我最喜欢的 Bea Stollnitz article on WPF databinding debugging没有建议我可以用于这个特定问题的任何东西。

最佳答案

当 DataContext 更改时,ComboBoxes 出现空白时,我遇到了同样的问题。我有一个相对简单的解决方案,它使用我编写的名为“ComboBoxFixer”的类。一旦实现,您可以通过简单地替换这个来解决这个问题:

<ComboBox ItemsSource="..." SelectedItem="..." />

有了这个:
<ComboBox ItemsSource="..." my:ComboBoxFixer.SelectedItem="..." />

问题解释

您的 ComboBoxes 出现空的原因是未设置 ItemsSource 时正在评估 SelectedItems 绑定(bind)。这可以通过延迟与 SelectedItems 之间的数据传输直到所有其他数据绑定(bind)完成后才能解决。

如何实现 ComboBoxFixer

我的 ComboBoxFixer 类是使用我编写的通用依赖属性同步器类实现的。我的 DependencyPropertySynchronizer 类具有以下接口(interface):
public class DependencyPropertySynchronizer
{
public DispatcherPriority Priority { get; set; }
public DependencyProperty AutoSyncProperty { get; set; }

public DependencyProperty Register(...
public DependencyProperty RegisterAttached(...
public DependencyPropertyKey RegisterReadOnly(...
public DependencyPropertyKey RegisterAttachedReadOnly(...
}

并且通常这样使用:
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));
}

上面的代码将导致任何给定对象的附加的幸福和快乐属性保持同步:无论何时设置幸福或快乐,另一个将在 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

附加说明

在某些情况下,如果您实际上是在切换 ItemsSource,则 SelectedItem 可能比正确值更晚地设置为 null。这可以通过向 DependencyObjectSynchronizer 添加验证功能来解决,然后在同步期间使用它来忽略空值。

关于c# - 数据绑定(bind)到不同 UserControl 中的 ObservableCollection - 如何保留当前选择?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2480450/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com