在WPF中在ListView内填充ComboBox的问题

时间:2019-07-08 14:19:55

标签: wpf xaml listview data-binding combobox

我希望有人可以帮助我解决这个问题。当绑定源只有一个值时,combox似乎仅将一项作为单个字符列出。如果是两个或更多,它将正确列出项目。

这里是遇到类似问题的人的两个链接。 Link 1 Link 2

<DataTemplate>
  <ComboBox ItemsSource="{Binding 'Clusters'}" 
   SelectedItem="{Binding Path='TargetCluster', Mode=TwoWay}"
   Width="145"
/>

这是商品来源

$vCenters = @()
        Foreach ($vCenter in $VDIEnvironments) {
           $vCenter | 
              Add-Member -MemberType NoteProperty -Name TargetCluster -Value (
                 $clusters | ? VCName -like $vCenter.Name
              )[0].Name -Force
           $vCenter | 
              Add-Member -MemberType NoteProperty -Name Clusters -Value $(
                 $clusters | ? VCName -like $vCenter.Name
              ).Name -Force
           $vCenter | 
              Add-Member -MemberType NoteProperty -Name TargetDatastore -Value $(
                 $datastores | ? VCName -like $vCenter.Name | Sort-Object -Descending FreeSpaceMB
              )[0].Name -Force
           $vCenter | 
              Add-Member -MemberType NoteProperty -Name Datastores -Value $(
                 $datastores | ? VCName -like $vCenter.Name
              ).Name -Force 
           $vCenter | 
              Add-Member -MemberType NoteProperty -Name TargetPortgroup -Value (
                 $portgroups | ? VCName -like $vCenter.Name | Sort-Object -Descending NumPorts
              )[0].Name -Force
           $vCenter | 
              Add-Member -MemberType NoteProperty -Name Portgroups -Value $(
                 $portgroups | ? VCName -like $vCenter.Name
              ).Name -Force

           $vCenters += $vCenter
        }

填充数据网格

            $SelectedVCenters = $VCenters | 
               Where-Object Env -like $WPFboxEnvironment.Text | 
               Where-Object Datastores -ne $Null
            $SelectedVCenters | ForEach-Object {
               $WPFboxSrcVCenter.Items.Add($_.Name)
               $WPFlistTgtVCenters.Items.Add($_)
               $WPFlistTgtVCenters.SelectedItems.Add($_)
            }    

2 个答案:

答案 0 :(得分:0)

感谢您的澄清。我和我的同事最终为所有vCenter添加了一个空群集,以解决此问题。不是最佳解决方案,但它可以解决我们遇到的两个问题。

$clusters = Get-Cluster | Select-Object Name, Uid

$clusters | ForEach-Object {
   $_ | Add-Member -MemberType NoteProperty -Name VCName -Value $_.Uid.split('@')[1].split(':')[0]
}

$uniqueVCs = $clusters | select VCName | sort VCName -Unique

foreach ($VC in $uniqueVCs) {
   $clusterplaceholder = [pscustomobject]@{
      'Name'   = "Select a cluster"
      'Uid'    = " "
      'VCName' = $VC.VCName
   }
   $clusters += $clusterplaceholder
}

$clusters = $clusters | sort VCName, Uid

答案 1 :(得分:-1)

通常在将ItemsControl.ItemsSource绑定到string时发生。 ItemsControl内部访问按索引绑定到ItemsSource的集合的副本,因为它必须为每个数据项(ItemContainerGenerator)创建一个容器,以便将数据呈现为Visual个对象。
由于string实现了类似

的索引器

public char this[int index] { get; }

,可通过索引(如集合或数组)进行访问。

现在,将string绑定到ItemsControl.ItemsSource时,string被复制到ItemsControl.Items集合中并传递到内部的ItemContainerGenerator负责创建视觉项目,这些视觉项目最终呈现为数据的视觉表示。该ItemContainerGeneratorstring值视为一个集合(因为string实现了IEnumerable),并通过索引对其进行访问。由于实现了索引器,string将返回其基础字符,然后生成器为每个字符创建一个容器。这就是string看起来分开的原因。

请确保您始终绑定到string的集合,但切勿直接绑定到string,以避免此行为。

用于显示字符串值和用于绑定的字符串集合的视图模型

class ViewModel : INotifyPropertyChanged
{
    private string stringValue;
    public string StringValue
    {
      get => this.stringValue;
      set
      {
        this.stringValue= value;
        OnPropertyChanged();
      }
    }

    private ObservableCollection<string> stringValues;
    public ObservableCollection<string> StringValues
    {
      get => this.stringValues;
      set
      {
        this.stringValues= value;
        OnPropertyChanged();
      }
    }
}

MainWindow.xaml,其中DataContextViewModel

<!-- This ComboBox will display the single characters of the string value (each item is a character)-->
<ComboBox x:Name="comboBox" ItemsSource="{Binding StringValue}" />

<!-- This ComboBox will display the strings of the StringValues collection (each item is a complete string) -->
<ComboBox x:Name="comboBox" ItemsSource="{Binding StringValues}" />

ComboBox(通常为ItemsControl)的显示项目实际上是容器。容器是数据的可视表示形式,并且像UserControl一样复杂。容器具有BorderBackgroundPaddingMargin等。它是一个Visual,由其他Visuals(或控件)组成。单独的string不能这样呈现(具有字体,字体颜色,背景等)。

因此,ItemsControl必须为每个数据对象创建一个可视容器。
这是由ItemsControl.ItemsPanel完成的,实际上使用ItemContainerGenerator来完成此操作。因此,内部ComboBox(或ItemsControl.ItemsPanel)访问ItemsControl.Items的绑定集合,以创建如下所示的容器:

IItemContainerGenerator generator = this.ItemContainerGenerator;    
GeneratorPosition position = generator.GeneratorPositionFromIndex(0);

using (generator.StartAt(position, GeneratorDirection.Forward, true))    
{    
    DependencyObject container = generator.GenerateNext();    
    generator.PrepareItemContainer(container);    
}

如您所见,生成器按索引访问项目。在内部,生成器访问ItemsControl.ItemsItemContainerGenerator.ItemsInternal)的副本,以检索应由容器托管的数据。这样(在生成器内部)看起来像:

object item = ItemsInternal[position];

由于string实现了索引器,因此您也可以像访问数组一样访问string

var someText = "A String";
char firstCharacter = someText[0]; // References 'A' from "A String"

因此,现在从上方查看容器生成器代码,现在您可以了解行的效果

GeneratorPosition position = generator.GeneratorPositionFromIndex(0);

generator.StartAt(position, GeneratorDirection.Forward, true)

string上有一个位置,位置是实际的项目索引:它逐个字符地检索以将它们映射到容器。

这是ItemsControl如何处理源集合的简化说明。