UWP XAML Combobox IntemsSource从另一个线程进行管理



上下文

网络上是用UDP定期宣传其名称的服务器。

数据报在1967年的端口上,并包含一个类似的字符串:

UiProxy SomeServerMachineName

添加了新的条目,现有条目已更新,而陈旧的条目则是可观察的收藏中的年龄,该集合用作XAML组合框的物品。

这是组合框

<ComboBox x:Name="comboBox" ItemsSource="{Binding Directory}" />

这是支持代码。例外处理人员包裹了所有危险的东西,但在这里简洁地省略了。

public class HostEntry
{
  public string DisplayName { get; set;}
  public HostName HostName { get; set; }
  public DateTime LastUpdate { get; set; }
  public HostEntry(string displayname, HostName hostname)
  {
    DisplayName = displayname;
    HostName = hostname;
    LastUpdate = DateTime.Now;
  }
  public override string ToString()
  {
    return DisplayName;
  }
}
HostEntry _selectedHost;
public HostEntry SelectedHost
{
  get { return _selectedHost; }
  set
  {
    _selectedHost = value;
    UpdateWriter();
  }
}
async UpdateWriter() {
  if (_w != null)
  {
    _w.Dispose();
    _w = null;
    Debug.WriteLine("Disposed of old writer");
  }
  if (SelectedHost != null)
  {
    _w = new DataWriter(await _ds.GetOutputStreamAsync(SelectedHost.HostName, "1967"));
    Debug.WriteLine(string.Format("Created new writer for {0}", SelectedHost));
  }
}
ObservableCollection<HostEntry> _directory = new ObservableCollection<HostEntry>();
public ObservableCollection<HostEntry> Directory
{
  get { return _directory; }
}
private async void _ds_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
  if (_dispatcher == null) return;
  await _dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
  {
    var dr = args.GetDataReader();
    var raw = dr.ReadString(dr.UnconsumedBufferLength);
    var s = raw.Split();
    if (s[0] == "UiProxy")
    {
      if (_directory.Any(x => x.ToString() == s[1]))
      { //update
        _directory.Single(x => x.ToString() == s[1]).LastUpdate = DateTime.Now;
      }
      else
      { //insert
        _directory.Add(new HostEntry(s[1], args.RemoteAddress));
      }
      var cutoff = DateTime.Now.AddSeconds(-10);
      var stale = _directory.Where(x => x.LastUpdate < cutoff);
      foreach (var item in stale) //delete
        _directory.Remove(item);
    }
  });
}

集合开始空。

从SelecteShost销毁的设置器中调用的UpdateWrite方法(如有必要),并在datagramsocket周围创建(如果可能的话)dataWriter,该数据量涉及datagramsocket,该datagramsocket针对Selectedhost的值所描述的地址。

目标

自动选择添加值时,列表停止为空。

列表也可以变为空。发生这种情况时,选择必须以-1的选定索引返回到NULL。

在事物的立场上,列表被管理,并且可以从列表中交互式选择服务器。

目前我将Selected Host设置为这样,但我敢肯定它可以通过绑定来完成。

private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
  SelectedHost = comboBox.SelectedItem as HostEntry;
}

selectedhost调用createWriter的设置器方法,该方法管理在其他地方将数据发送到所选主机的对象。我已经从设定器打电话给它,因为它必须始终在价值发生变化之后,而且在任何其他时间都会发生。它是一种方法,因此可以是异步。

我可以将其移至SelectionChanged处理程序,但是如果我这样做,那么我该如何保证执行顺序?

问题

尝试编程设置组合框的选择时会出现错误。我正在划定UI线程,但事情仍然不好。正确的方法是什么?我已经尝试设置SelectedIndex和Selected Value。

当我尝试编程设置组合框的选择时,我会出现错误。

你好吗?在代码方面,只要您注定要在该索引上包含一个项目:

myComboBox.SelectedIndex = 4;

,但我确定它可以通过绑定

来完成

是的,看起来您忘了实现InotifyPropertyChanged。另外,由于您正在使用UWP,因此有一种新的改进的绑定语法Bind,而不是Binding在此处了解更多:https://msdn.microsoft.com/en-us/windows/uwindows/uwdata-data-binding/data-binding/data-binding-in-data-binding-in-data-in-data-in-depth-in-data-in-depth-in

<ComboBox x:Name="comboBox" ItemsSource="{Binding Directory}" 
     SelectedItem="{Binding SelectedHost}" />
public event PropertyChangedEventHandler PropertyChanged;
HostEntry _selectedHost;
public HostEntry SelectedHost
{
  get { return _selectedHost; }
  set
  {
    _selectedHost = value;
    RaiseNotifyPropertyChanged();
    // What is this? propertys should not do things like this CreateWriter();
  }
}
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

最新更新