【问题标题】:UWP XAML Combobox ItemsSource management from another threadUWP XAML Combobox ItemsSource 管理来自另一个线程
【发布时间】:2016-10-22 12:49:48
【问题描述】:

上下文

网络上的服务器定期使用 UDP 公布其名称。

数据报从 1967 端口进入并包含如下字符串:

UiProxy SomeServerMachineName

添加了新条目,更新了现有条目,并且陈旧的条目在用作 XAML 组合框的 ItemsSource 的可观察集合中过期。

这是组合框

<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);
    }
  });
}

集合开始为空。

从 SelectedHost 的 setter 调用的 UpdateWrite 方法会销毁(如果需要)并在 DatagramSocket 周围创建(如果可能)一个 DataWriter,目标是 SelectedHost 的值所描述的地址。

目标

在添加值且列表不再为空时自动选择。

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

就目前而言,列表是受管理的,并且可以从列表中交互式地选择一个服务器。

目前我正在像这样设置 SelectedHost,但我确信它可以通过绑定来完成。

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

SelectedHost 的 setter 方法调用 CreateWriter,它管理在别处使用的对象以将数据发送到选定的主机。我从 setter 中调用了它,因为它必须始终在值更改后立即发生,并且不能在其他时间发生。它在一个方法中,所以它可以是异步的。

我可以将它移动到 SelectionChanged 处理程序,但如果我这样做了,我如何保证执行顺序?

问题

当我尝试以编程方式设置组合框的选择时出现错误。我正在编组到 UI 线程,但情况仍然不好。这样做的正确方法是什么?我试过设置 SelectedIndex 和 SelectedValue。

【问题讨论】:

  • 你遇到了什么错误?

标签: c# xaml uwp-xaml


【解决方案1】:

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

你做得怎么样?在代码隐藏中,只要您绑定的集合在该索引处有一个项目,这应该可以工作:

myComboBox.SelectedIndex = 4;

但我相信它可以通过绑定来完成

是的,它可以,看起来你忘了实现INotifyPropertyChanged。此外,由于您使用的是 UWP,因此有一个新的改进的绑定语法 Bind 而不是 Binding 在此处了解更多信息:https://msdn.microsoft.com/en-us/windows/uwp/data-binding/data-binding-in-depth

<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));
    }
}

【讨论】:

  • 更准确地说是我忘记了关于 INotifyPropertyChanged,我记得ObservableCollection真是个奇迹!我没有做过 XAML 绑定,因为 Silverlight 是一件事,而且我所有的书都在家里。谢谢你提醒我。
  • 我将 NotifyPropertyChanged 的​​名称更改为 RaiseNotifyPropertyChanged 并添加了 SelectedItem="{Binding SelectedHost}" 但缺少某些内容,当我以交互方式选择组合框值时未分配 SelectedHost,我在二传手,它没有被击中。
  • 请在您的问题中加入 XAML 和 C#
猜你喜欢
  • 2017-08-20
  • 2017-01-05
  • 2014-07-27
  • 1970-01-01
  • 2013-10-02
  • 2017-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多