【问题标题】:Can't bind listbox to ObservableCollection within a class无法将列表框绑定到类中的 ObservableCollection
【发布时间】:2015-04-14 06:53:51
【问题描述】:

我在将列表框绑定到多个类的 ObservableCollection 时遇到问题,基本上像:

Device.State.Menu.Items

作为测试,如果我在我的表单上创建一个独立的 Items 集合并绑定到它,那么它确实可以工作。

如果我使用我的完整对象并尝试绑定到上面的路径,它就不起作用。我看到它试图引发事件,但 PropertyChangedEventHandler 为空,就像它没有绑定一样,所以列表不会刷新。我尝试了使用 observablecollection/inotify 来处理 Items 类的不同方法。这是一个精简版:

    public class NetworkMenu
    {
        public string Title = "";
        private ObservableCollection<NetworkMenuItem> _items = new ObservableCollection<NetworkMenuItem>();
        public ObservableCollection<NetworkMenuItem> Items
        {
            get { return _items; }
        }
    }

    public class NetworkMenuItem : INotifyPropertyChanged
    {
        private int _index = 0;
        private string _title = "";
        private string _code = "";

        public event PropertyChangedEventHandler PropertyChanged;

        public NetworkMenuItem(int index, string title, string code = "")
        {
            _index = index;
            _title = title;
            _code = code;
        }

        public int Index
        {
            get { return _index; }
            set
            {
                if (_index != value)
                {
                    _index = value;
                    OnPropertyChanged("Index");
                }
            }
        }

        public string Title
        {
            get { return _title; }
            set
            {
                if (_title != value)
                {
                    _title = value;
                    OnPropertyChanged("Title");
                }
            }
        }

        public string Code { get; set; }

        protected virtual void OnPropertyChanged(string property)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(property));
        }
    }

这就是我绑定它的方式:

        this.Browser.ItemsSource = device.State.Menu.Items;

PropertyChangedEventHandler 为空,就像没有绑定一样。

但是在我的测试中,如果我绕过设备类并在我的主窗体上创建一个 Items 集合,通过按下按钮手动添加菜单项:

    ObservableCollection<Device.NetworkMenuItem> items = new ObservableCollection<Device.NetworkMenuItem>();

绑定有效

我仍然遇到问题 - 我将数据上下文更改为设备

更改了 XAML:

    <ListBox HorizontalAlignment="Left" Height="655" Margin="224,57,0,0" VerticalAlignment="Top" Width="370" x:Name="Browser" ItemsSource="{Binding State.Menu.Items}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Path=Title}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

设备下的状态改变:

    private DeviceState _state = new DeviceState();
    public DeviceState State
    {
        get { return _state; }
        set { _state = value; }
    }

状态下的更改菜单:

        private NetworkMenu _menu = new NetworkMenu();
        public NetworkMenu Menu
        {
            get { return _menu; }
            set { _menu = value; }
        }

另一个更新,进一步的测试显示绑定在我创建连接之前确实有效,所以我相信这是任务/线程的问题,我从未处理过主要来自 .net 2.0 的问题,我重新 -编写一个较旧的 silverlight WP7 应用程序。

一旦我开始循环监控套接字绑定就会停止工作:

            await Task.Factory.StartNew(WaitForMessage);

其他一切都按预期工作

    public async void Connect(string p_hostName, string p_port)
    {
        hostName = p_hostName;
        port = p_port;

        socket = new StreamSocket();
        try
        {                
            await socket.ConnectAsync(new HostName(hostName), port);
            OnConnect(new ConnectArgs(true));
            await Task.Factory.StartNew(WaitForMessage);
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Connect Error: " + ex.Message);
            OnConnect(new ConnectArgs(false));
        }
    }

    private async void WaitForMessage()
    {
        if (socket == null)
            return;

        string trailingMessage = null;

        DataReader reader = new DataReader(socket.InputStream);
        reader.InputStreamOptions = InputStreamOptions.Partial;
        //try
        {
            while (true)
            {
                await reader.LoadAsync(BufferSize);

                byte[] bData = new byte[reader.UnconsumedBufferLength];
                reader.ReadBytes(bData);

                string data = Encoding.UTF8.GetString(bData, 0, bData.Length);

                bool bufferWasPreviouslyFull = !string.IsNullOrEmpty(trailingMessage);
                if (bufferWasPreviouslyFull)
                {
                    trailingMessage = null;
                }

                if (string.IsNullOrWhiteSpace(data))
                {
                    OnDisconnect(new EventArgs());
                    break;
                }

                var messages  = new List<string>(data.Split("\n\r".ToCharArray(), StringSplitOptions.None));

                var lastMessage = messages.LastOrDefault();
                bool isBufferFull = !string.IsNullOrWhiteSpace(lastMessage);
                if (isBufferFull)
                {
                    trailingMessage = lastMessage;
                    messages.Remove(lastMessage);
                }

                foreach (var message in messages)
                {
                    if (string.IsNullOrWhiteSpace(message))
                        continue;

                    ProcessMessage(message);
                }

            }
        }
        //catch (Exception ex)
        //{
        //    Debug.WriteLine("WaitForMessage Error: " + ex.Message);
        //    OnDisconnect(new EventArgs());
        //}
    }

最终更新......现在工作。还有一个关于如何重置菜单的问题,因此使用上述属性并使用 itemssource = device.State.Menu.Items, no datacontext,它现在可以正常工作

【问题讨论】:

  • this.Browser.ItemsSource = device.State.Menu.Items; --> 这不是 BINDING,您只需设置 itemssource。
  • 有问题并不能解释太多,如果您将 datacontext 设置为设备实例,您应该会在调试输出窗口中看到绑定错误
  • 我的意思是它做的和以前一样。调试输出窗口中仍然没有任何内容,将级别从警告更改为全部

标签: c# wpf data-binding


【解决方案1】:

您的 Items ObservableCollection 是一个字段,请将其设为属性,您不能仅将字段绑定到属性。

根据您上次的更新,您并没有真正绑定任何东西,请将其设置为 this.DataContext = device;

在您的 XAML 中将项目源绑定为

<ListBox ItemsSource="{Binding State.Menu.Items}"></ListBox>

并确保 State MenuItems 是公共属性。

【讨论】:

  • 我曾在某个时候尝试过:private ObservableCollection&lt;NetworkMenuItem&gt; _items = new ObservableCollection&lt;NetworkMenuItem&gt;(); public ObservableCollection&lt;NetworkMenuItem&gt; Items { get { return _items; } } 它使用上面的代码再次对其进行了测试,但我仍然看到同样的问题
  • @Jason 然后请编辑您上面的代码并将其设为属性并分享您的 xaml
  • 还要注意输出窗口出现绑定错误,你可以通过工具栏中的Debug >> Windows >> Output Window来显示输出窗口,然后你应该在运行时看到BindingExpression路径错误
  • 我在窗口中看不到任何内容 - 我已验证显示绑定错误,并尝试使用 App.Current.DebugSettings.BindingFailed 但从未调用过
  • @Jason 所以没有System.Windows.Data Error: 40 : BindingExpression path error:?如果您没有看到,并且您的 DataContext 设置为包含 Device 属性的 ViewModel,那么您看不到任何内容的唯一原因是您的列表为空!
猜你喜欢
  • 2018-08-13
  • 2011-05-07
  • 2012-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-02
  • 2012-07-04
相关资源
最近更新 更多