无法将列表框绑定到 class 中的 ObservableCollection
Can't bind listbox to ObservableCollection within a class
我在将列表框绑定到 ObservableCollection 几个 class 深度时遇到问题,基本上像:
Device.State.Menu.Items
作为测试,如果我在我的表单上创建一个独立的 Items 集合并绑定到它,那么它确实有效。
如果我使用我的完整对象并尝试绑定到上面的路径,它不起作用。我看到它尝试引发事件,但 PropertyChangedEventHandler 为 null,就像它未绑定一样,因此列表不会刷新。我尝试了用 observablecollection/inotify 处理项目 class 的不同方法。这是精简版:
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 为 null,就像它没有绑定一样。
但是在我的测试中,如果我绕过设备 class 并在我的主窗体上创建一个项目集合,通过按下按钮手动添加菜单项:
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; }
}
另一个更新,进一步的测试表明在我创建连接之前绑定确实有效,所以我相信这是 tasks/threading 的问题,我从来没有处理过主要来自 .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,没有数据上下文,它现在可以正常工作
您的 Items ObservableCollection 是一个字段,将其设为 属性,您不能仅将字段绑定到属性。
根据你上次的更新你并没有真正绑定任何东西,让它成为 this.DataContext = device;
在您的 XAML 中将项目源绑定为
<ListBox ItemsSource="{Binding State.Menu.Items}"></ListBox>
并确保 State
Menu
和 Items
是 public 属性。
我在将列表框绑定到 ObservableCollection 几个 class 深度时遇到问题,基本上像:
Device.State.Menu.Items
作为测试,如果我在我的表单上创建一个独立的 Items 集合并绑定到它,那么它确实有效。
如果我使用我的完整对象并尝试绑定到上面的路径,它不起作用。我看到它尝试引发事件,但 PropertyChangedEventHandler 为 null,就像它未绑定一样,因此列表不会刷新。我尝试了用 observablecollection/inotify 处理项目 class 的不同方法。这是精简版:
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 为 null,就像它没有绑定一样。
但是在我的测试中,如果我绕过设备 class 并在我的主窗体上创建一个项目集合,通过按下按钮手动添加菜单项:
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; }
}
另一个更新,进一步的测试表明在我创建连接之前绑定确实有效,所以我相信这是 tasks/threading 的问题,我从来没有处理过主要来自 .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,没有数据上下文,它现在可以正常工作
您的 Items ObservableCollection 是一个字段,将其设为 属性,您不能仅将字段绑定到属性。
根据你上次的更新你并没有真正绑定任何东西,让它成为 this.DataContext = device;
在您的 XAML 中将项目源绑定为
<ListBox ItemsSource="{Binding State.Menu.Items}"></ListBox>
并确保 State
Menu
和 Items
是 public 属性。