【问题标题】:Binding an ObservableCollection of Strings to a ListBox in WPF将字符串的 ObservableCollection 绑定到 WPF 中的 ListBox
【发布时间】:2014-11-06 14:22:06
【问题描述】:

我目前正在尝试掌握 MVVM 的概念。因此,我已经阅读了几篇博客并查看了一些项目。但是,我仍然不知道如何应用这个概念。

现在,我正在尝试将字符串值的 ObservableCollection 绑定到 ListBox,以便逐行列出它们的值。我的 ViewModel 目前看起来像这样:

namespace TestApp.ViewModel
{
    class StatusViewModel : NotifyPropertyChanged
    {
        private string _newMsg;
        private readonly ObservableCollection<string> _history = new ObservableCollection<string>();

        public string Print
        {
            get { return _newMsg; }
            set
            {
                _newMsg = value;
                RaisePropertyChangedEvent("History");
                AddToHistory(_newMsg);
            }
        }

        public IEnumerable<string> History
        {
            get { return _history; }
        }

        private void AddToHistory(string item)
        {
            if (!_history.Contains(item))
                _history.Add(item);
        }
    }
}

namespace TestApp.ViewModel
{
    public class NotifyPropertyChanged : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChangedEvent(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

在视图中,我想将 ListBox 绑定到 History。这是我的 XAML:

<UserControl x:Class="TestApp.View.StatusView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:vm="clr-namespace:TestApp.ViewModel" mc:Ignorable="d">
    <UserControl.Resources>
        <vm:StatusView x:Key="statusView"/>
    </UserControl.Resources>
    <Grid DataContext="{StaticResource statusView}">
        <GroupBox Header="StatusView">
            <ListBox x:Name="StatusListBox" ItemsSource="{Binding History, Source={StaticResource statusView}}"/>
        </GroupBox>
    </Grid>
</UserControl>

当我启动 TestApp 时,我需要访问我的 StatusViewModel 的实例,以便将字符串添加到我的 ObservableCollection。我想知道这是怎么做到的:

using TestApp.ViewModel;

namespace TestApp.Controller
{
    public partial class Startup
    {
        private void StartTestApp()
        {
            // from where do I get my 'statObj' in order to do:
            statObj.Print = "something";
        }
    }
}

如何将我的 StatusViewModel 对象中的字符串 ObservableCollection 绑定到列表框?

更新:

感谢大家的精彩 cmets!现在,我知道我需要持有我的 ViewModel 的一个实例,以便从 View Controller 访问它。但是,我仍在努力以正确的方式做到这一点。## Heading ##

现在,我首先在用户控件的代码隐藏中创建实例。虽然它正在工作,但我不喜欢我必须在我的视图中引用 ViewModel。我想,MV​​VM 的全部意义在于这样做。

此外,我想知道如何在视图之外访问我新实例化的 StatusViewModel 状态,例如在名为 Controller 的不同命名空间中。

using System.Windows.Controls;
using TestApp.ViewModel;

namespace TestApp.View
{
    /// <summary>
    /// Interaction Logic for StatusView.xaml
    /// </summary>
    public partial class StatusView : UserControl
    {
        public StatusView()
        {
            InitializeComponent();

            this.DataContext = new StatusViewModel();
        }

        public TestApp.ViewModel.StatusViewModel State
        {
            get { return (DataContext as TestApp.ViewModel.StatusViewModel); }
        }
    }
}

【问题讨论】:

  • 绑定将在 Status: &lt;vm:Status x:Key="status"/&gt; 的这个实例上工作,并且为了测试你创建 Status 的不同实例 并在上面更改 Print。它们不是同一个对象
  • 有道理!但是如何在我的StartTestApp 方法中编辑现有的状态对象?我的 start 方法位于不同的命名空间中,名为 TestApp.Controller
  • 您需要获取该实例。取决于你的设计。有些人使用包含视图模型定位器的框架。我通常将我的 VM 定义为 app.xaml 中的资源,然后将它们相互绑定,因此 VM X 具有对 VM Y 的引用。有些人在视图的构造函数中构造它们,因此他们具有对它的引用.随心所欲。

标签: c# wpf xaml mvvm listbox


【解决方案1】:

试试

public ObservableCollection<string> History
{
    get { return _history; }
}
private void AddToHistory(string item)
{
    if (!History.Contains(item)) History.Add(item);
}

【讨论】:

    【解决方案2】:

    将您的 XAML 更改为:

    <UserControl x:Class="TestApp.View.Status"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:vm="clr-namespace:TestApp.ViewModel" mc:Ignorable="d">
    <UserControl.DataContext>
        <vm:Status />
    </UserControl.DataContext>
    <Grid>
        <GroupBox Header="Status">
            <ListBox x:Name="StatusListBox" ItemsSource="{Binding History}"/>
        </GroupBox>
    </Grid>
    

    访问您的 viemodel 的代码应包含以下内容:

    Status status = DataContext as Status;
    if (status != null)
       status.Print = "Hello";
    

    然后它似乎工作:

    当你想访问这个用户控件的状态实例时,给用户控件添加一个属性:

    public TestApp.ViewModel.Status State // Status gives probably naming conflict
    { 
        get
        {
            return (DataContext as TestApp.ViewModel.Status);
        }
    }
    

    【讨论】:

    • 感谢您的快速回答!不幸的是,我的 ListBox 中仍然没有显示任何消息:(
    • 你没有设置DataContext。哦,你做了......对不起。
    • 我应该在哪里添加if (DataContext != null) ...
    • 那个空检查不正确。应该是var thisIsHackyAnyhowSoWhyDoICareIAskYou = DataContext as Status; if(thisIsHackyAnyhowSoWhyDoICareIAskYou != null) thisIsHackyAnyhowSoWhyDoICareIAskYou.Print = "DERP HACK ALERT";
    • 例如,在用户控件的代码隐藏中。至少,您需要一种方法来以某种方式引用实例化的用户控件。例如,从您放置用户控件的窗口中。
    猜你喜欢
    • 2014-08-02
    • 1970-01-01
    • 2013-12-31
    • 2015-08-04
    • 1970-01-01
    • 1970-01-01
    • 2012-12-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多