如何在列表框 DataTemplate 中使用多个词典?
How to use multiple dictionaries in a listbox DataTemplate?
我想知道是否可以在列表框数据模板中使用两个词典。我想在文本框中使用 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>
只需创建一个包含这两个值的 class 并将其用作 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>
这很难,所以我建议您为您的 ListBox 创建特定的 class 作为 DataContext。
在你的情况下你可以尝试什么:
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; }
}
在您的 xaml 中设置 DataTemplate 时,其 DataContext 被设置为 ItemsSource 的单个条目。在您的情况下,这是 KeyValuePair。您也可以使用 MultiBinding 绑定到您的 EnabledNames 字典,并使用转换器将您的密钥从 EnabledNames 转换为 bool 值:
<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 方法,但是不可能转换回布尔值。因此,同样,最简单的方法是创建特定的 class 来代表您的 ListBox 的单行:
public class Person
{
public string ID { get; set; }
public string Name { get; set; }
public bool IsEnabled { get; set; }
}
我想知道是否可以在列表框数据模板中使用两个词典。我想在文本框中使用 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>
只需创建一个包含这两个值的 class 并将其用作 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>
这很难,所以我建议您为您的 ListBox 创建特定的 class 作为 DataContext。
在你的情况下你可以尝试什么:
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; } }
在您的 xaml 中设置 DataTemplate 时,其 DataContext 被设置为 ItemsSource 的单个条目。在您的情况下,这是 KeyValuePair。您也可以使用 MultiBinding 绑定到您的 EnabledNames 字典,并使用转换器将您的密钥从 EnabledNames 转换为 bool 值:
<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 方法,但是不可能转换回布尔值。因此,同样,最简单的方法是创建特定的 class 来代表您的 ListBox 的单行:
public class Person
{
public string ID { get; set; }
public string Name { get; set; }
public bool IsEnabled { get; set; }
}