【问题标题】:How to use multiple dictionaries in a listbox DataTemplate?如何在列表框 DataTemplate 中使用多个字典?
【发布时间】:2015-10-16 23:05:57
【问题描述】:

我想知道是否可以在列表框数据模板中使用两个字典。我想在文本框中使用 Names 的值,并在复选框中使用 EnabledNames 的值。这可能吗?如果是这样,我将如何去做?

一些示例数据是:

Dictionary<string, string> Names = new Dictionary<string, string>()
            {
                { "4EG25","John" },
                {"923OT", "Joe" }
            };
            Dictionary<string, bool> EnabledNames = new Dictionary<string, bool>()
            {
                { "4EG25",false },
                {"923OT", true}
            };

以及我想如何以如下方式使用:

<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="359" VerticalAlignment="Top" Width="673" Margin="0,0,-0.333,-0.333" ItemsSource="{Binding Path=Names, Mode=OneWay}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <CheckBox IsChecked="{Binding Path=EnabledNames[ItemsSource.Key].Value}" />
                                    <TextBlock Text="{Binding Path=ItemsSource.Value}"/>
                                </StackPanel>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>

【问题讨论】:

  • 您为什么不想创建一个带有 Name 和 IsEnabled 属性的简单视图模型类?然后将 ListBox 绑定到此类的集合。

标签: c# wpf xaml data-binding listbox


【解决方案1】:

只需创建一个包含这两个值的类并将其用作 ItemsSource

class Name
{
    public string Value { get; set; }

    public bool Enabled { get; set; }
}

public IEnumerable<Name> TheNames
{
    get { return Names.Select(n => new Name {Value = n.Value, Enabled = EnabledNames[n.Key]}); }
}


<ListBox ItemsSource="{Binding Path=TheNames, Mode=OneWay}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <CheckBox IsChecked="{Binding Path=Enabled}" />
                <TextBlock Text="{Binding Value}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

【讨论】:

    【解决方案2】:

    这很难,所以我建议您为您的 ListBox 创建特定的类作为 DataContext。

    你可以在你的情况下尝试什么:

    1. WPF 绑定只能对属性进行(您的字典现在是字段,因此您的绑定将不起作用。您的 ViewModel 可能是这样的:

      public class ViewModel
      {
          public ViewModel()
          {
              Names = new Dictionary<string, string>()
              {
                  { "4EG25","John" },
                  {"923OT", "Joe" }
              };
              EnabledNames = new Dictionary<string, bool>()
              {
                  { "4EG25",false },
                  {"923OT", true}
              };
          }
      
          public Dictionary<string, string> Names { get; set; }
          public Dictionary<string, bool> EnabledNames { get; set; }
      }
      
    2. 在您的 xaml 中,当您设置 DataTemplate 时,其 DataContext 设置为您的 ItemsSource 的单个条目。在您的情况下,这是 KeyValuePair。您也可以使用 MultiBinding 绑定到您的 EnabledNames 字典并使用转换器将您的 Key 从 EnabledNames 转换为 bool Value:

      <Window x:Class="Test31641637.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:local="clr-namespace:Test31641637"
              Title="MainWindow" Height="350" Width="525"
              Name="mw">
      
          <Window.Resources>
              <ResourceDictionary>
                  <local:MultiDictionaryConverter x:Key="multiDictionaryConverter" />
              </ResourceDictionary>
          </Window.Resources>
          <Window.DataContext>
              <local:ViewModel />
          </Window.DataContext>
          <ListBox x:Name="listBox" ItemsSource="{Binding Names}">
              <ListBox.ItemTemplate>
                  <DataTemplate>
                      <StackPanel Orientation="Horizontal">
                          <CheckBox >
                              <CheckBox.IsChecked>
                                  <MultiBinding Converter="{StaticResource multiDictionaryConverter}" ConverterParameter="">
                                      <Binding Path="Key" Mode="OneWay"/>
                                      <Binding ElementName="mw" Path="DataContext.EnabledNames"/>
                                  </MultiBinding>
                              </CheckBox.IsChecked>
                          </CheckBox>
                          <TextBlock Text="{Binding Path=Value}"/>
                      </StackPanel>
                  </DataTemplate>
              </ListBox.ItemTemplate>
          </ListBox>
      </Window>
      

    和 IMultiValueConverter:

    public class MultiDictionaryConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (values.Length == 2 && values[0] is string && values[1] is Dictionary<string, bool>)
            {/*
                ((Dictionary<string, bool>)values[1])[values[0] as string] =
                    !((Dictionary<string, bool>)values[1])[values[0] as string];*/
    
                return ((Dictionary<string, bool>)values[1])[values[0] as string];
            }
    
            return false;
        }
    
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }
    }
    

    我想这是最简单的方法(但并不容易)它不会起作用,因为当您单击 ListBox 中的 CheckBox 时,将调用 ConvertBack 方法,但 不可能 转换回布尔值。因此,同样,最简单的方法是创建代表 ListBox 单行的特定类:

    public class Person
    {
        public string ID { get; set; }
    
        public string Name { get; set; }
    
        public bool IsEnabled { get; set; }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-03-12
      • 1970-01-01
      • 2020-10-05
      • 2019-03-12
      • 1970-01-01
      • 2019-02-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多