【问题标题】:Loading listboxes inside tabitems - which event to use?在 tabitems 中加载列表框 - 使用哪个事件?
【发布时间】:2010-02-23 23:19:19
【问题描述】:

假设我有一个包含一个窗口的应用程序。窗口内部是一个 tabcontrol,带有三个 tabitem。每个 tabitem 内部都有一个用户控件。

在一个标签中,我添加了颜色。在下一个选项卡中,我添加了水果。在第三个选项卡中,我有关系,用户可以在其中添加水果和颜色之间的链接。这种关系显示在一个列表框中,如:

Apple > Red
Pear  > Green

在同一选项卡的下方,我缺少水果列表框和缺少颜色列表框...即已添加但未在关系中链接的水果或颜色。我应该解释一下,这些数据都存储在三个单独的文本文件中,fruits.txt、colors.txt 和relationships.txt。

我遇到的问题如下。目前,列表框等的填充发生在 Usercontrol_loaded 事件中。水果/颜色无关紧要,因为单击添加按钮后,列表会重新加载。问题出在关系屏幕上。

假设用户运行程序,然后单击关系选项卡以查看链接的内容。我们会说上面的例子已经在文本文件中。这样这种关系就显现出来了——而且没有遗漏的果实。用户然后单击水果选项卡并添加水果,然后单击颜色选项卡并添加颜色。然后移动到关系选项卡。 usercontrol_loaded 事件已经发生,因此这两个新添加的内容不会显示在列表框中。

如果我将代码移动到 GotFocus 事件,用户将无法在任何列表框中进行选择,因为它会不断加载,因为单击会触发事件。

除了提供刷新按钮之外,还有什么其他事件或方式可以让我在标签被“切换到”时刷新?

感谢阅读。

...

编辑 1: 如果我将数据绑定到我在代码隐藏中构建的缺失水果列表,我仍然会遇到同样的问题。每次他们跳出这个标签并返回它时,我都必须重新加载这个列表(因为他们可能已经添加了一种水果或一种颜色,现在已经丢失了)。

【问题讨论】:

    标签: c# wpf events listbox tabcontrol


    【解决方案1】:

    您需要了解 MVVM 和更改通知的工作原理。如果您在绑定到 UI 的视图模型类的可观察集合中跟踪所有这些东西,则不需要在 all 使用事件或代码隐藏。

    正如 wwosik 建议的那样,创建一个公开 ColorsFruitsRelationships 属性的类,这些属性都是可观察的集合。正如他/她没有建议但可能应该建议的那样,还公开MissingColorsMissingFruits 可观察集合。最后,公开SelectedColorSelectedFruit 的公共属性。

    创建绑定控件:

    <ListBox ItemsSource="{Binding Colors}" SelectedItem="{Binding SelectedColor}"/>
    <ListBox ItemsSource="{Binding Fruits}" SelectedItem="{Binding SelectedFruit}"/>
    <ListBox ItemsSource="{Binding Relationships}"/>
    <ListBox ItemsSource="{Binding MissingColors}"/>
    <ListBox ItemsSource="{Binding MissingFruits}"/>
    

    实现一个AddRelationship 方法,该方法添加一个由SelectedColorSelectedFruit 组成的新关系。它还应该从各自的 MissingColorsMissingFruits 集合中删除颜色和水果。创建一个调用此方法的命令并将其绑定到 UI 中的某些内容。

    就是这样。任何选项卡上的任何内容都无关紧要。用户查看事物的顺序无关紧要。当用户添加关系、水果或颜色时,UI 将得到更新。

    【讨论】:

    • 所以我猜你是在暗示 addfruit/color 方法改变了缺少的水果/颜色列表。我还想知道 {Binding Fruits} 行如何识别该属性所在的类?我曾假设这些必须坐在试图显示它们的任何东西的代码隐藏中,但是从我从这些回复中慢慢了解到的情况绝对不是这样吗?欢呼
    • 我不是在暗示,而是在明确地说出来(见第 2 句第 4 段)。有很多方法可以让绑定知道属性所在的类,但到目前为止,最简单的方法是在包含所有绑定控件到该类实例的任何对象上设置DataContext。如果你的类的构造函数初始化了自己,它就像&lt;object.DataContext&gt;&lt;local:MyClass/&gt;&lt;/object.DataContext&gt; 一样简单。
    【解决方案2】:

    您需要将列表框绑定到 ViewModel 中的数据。这样,WPF 框架就超越了对更新数据时刻的检测。

    【讨论】:

    • 但是有逻辑可以确定哪些水果不在关系文件中。你是如何数据绑定的
    • 您需要一个单独的列表,因此您将丢失的水果绑定到丢失的水果列表。每当某些数据发生变化时,您都需要更新列表:用户重新加载数据或建立其他关系等。
    • 那也是同样的问题!检查列表的逻辑 - 它在哪里? Usercontrol_load - 那么绑定到的列表总是相同的。 GotFocus - 然后它是不可选择的。除非你说我必须在 xaml 中进行绑定 - 目前我在 UserControl_Loaded { listbox.ItemsSource = missingFruits; } missingFruits 是 ObservableCollection
    • 如果我删除 itemssource 后面的代码并像这样在 xaml 中设置: 它不起作用。我喜欢数据绑定。
    • 说真的,一旦你对数据绑定有了充分的了解,你就会崇拜它。在了解数据绑定和 MVVM 之前,我认为 WPF 是不可思议的困难;现在我认为这非常容易。
    【解决方案3】:

    WPF 不是 WinForms。您不会自己填充 ListBox。

    你有

    class MyData{
       ObservableCollection<Color> Colors;
       ObservableCollection<Fruit> Fruits;
       ObservableCollection<Pairs> Pairs;
    
       public void MatchCurrentSelection(){
            var selectedColor = CollectionViewSource.GetDefaultView(Colors).CurrentItem;
            var selectedFruit = CollectionViewSource.GetDefaultView(Fruits).CurrentItem;
            if(selectedColor != null && selectedFruit != null){
                 Colors.Remove(selectedColor);
                 Fruits.Remove(selectedFruit);
                 Pairs.Add(new Pair(selectedColor, selectedFruit));
            }
       }
    } 
    

    列表框

    <ListBox ItemsSource="{Binding Colors}" IsSynchronizedWithCurrentItem="true"/>
    <ListBox ItemsSource="{Binding Fruits}" IsSynchronizedWithCurrentItem="true"/>
    <ListBox ItemsSource="{Binding Pairs}"/>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-02
      • 1970-01-01
      • 2011-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多