【发布时间】:2020-01-24 14:13:48
【问题描述】:
我正在尝试使组合框与属性保持同步:
<ComboBox SelectedItem="{Binding StrokeSwatch}"...
这项工作除了组合框一直为空(如果框打开,则项目在此处,但没有当前/选定的项目),直到我手动选择一个值。
它应该显示红色样本和名称:
我找不到原因:SelectedItem 绑定到 (StrokeSwatch) 的属性有一个值,该值被该行使用,但组合框对这个值没有反应。
正在学习 WPF,希望对理解有所帮助。
代码...
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="300">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel Margin="10">
<StackPanel Orientation="Horizontal" Margin="10">
<TextBlock Text="Stroke:"/>
<ComboBox Margin="10,0,0,0" ItemsSource="{Binding SwatchesByName}" SelectedItem="{Binding StrokeSwatch}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Width="25" Fill="{Binding Brush}"/>
<TextBlock Margin="10,0,0,0" Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<Line Margin="10" X1="0" Y1="0" X2="200" Y2="100"
Stroke="{Binding StrokeSwatch.Brush}"
StrokeThickness="2"/>
</StackPanel>
</Window>
C#:
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
namespace WpfApp1 {
public partial class MainWindow : Window {
public MainWindow () {
InitializeComponent ();
}
}
public class ViewModel : INotifyPropertyChanged {
Swatch strokeSwatch;
public IEnumerable<Swatch> SwatchesByName { get => Swatches.ByName; }
public Swatch StrokeSwatch { get => strokeSwatch; set { strokeSwatch = value; RaisePropertyChanged (); } }
public event PropertyChangedEventHandler PropertyChanged;
public ViewModel () {
StrokeSwatch = Swatches.ColorToSwatch (Colors.Red);
}
void RaisePropertyChanged ([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke (this, new PropertyChangedEventArgs (propertyName));
}
}
static class Swatches {
public static IEnumerable<Swatch> ByName { get; }
static Swatches () {
ByName = from PropertyInfo pi in typeof (Colors).GetProperties ()
orderby pi.Name
select new Swatch (pi.Name, (Color) pi.GetValue (null, null));
}
public static Swatch ColorToSwatch (Color color) {
return ByName.First (sw => sw.Color == color);
}
}
public class Swatch {
SolidColorBrush brush;
public string Name { get; }
public Color Color { get; }
public SolidColorBrush Brush { get { if (brush == null) brush = new SolidColorBrush (Color); return brush; } }
public Swatch (string name, Color color) {
Name = name;
Color = color;
}
}
}
【问题讨论】:
-
确保
StrokeSwatch持有的实例实际上包含在SwatchesByName集合中。如果您不能保证,请覆盖 Swatch 类的 Equals 方法。 -
或者设置
SelectedValuePath="Name"和SelectedValue="{Binding StrokeSwatch.Name}"(而不是绑定SelectedItem)。 -
您也可以在静态 Swatches 构造函数中通过
ByName = ByName.ToList();强制进行初始枚举。 -
LINQ 表达式总是延迟执行。仅调用
ToList()、ToArray()或ToDictionary()或任何返回单个值的方法,例如Count()、First()或Max()或调用IEnumerable.GetEnumerator(例如foreach)将执行查询表达式。 -
这里的重点是
ByName.First(sw => sw.Color == color)独立于 ComboBox 的枚举枚举表达式。因此,您创建了两组不同的 Swatch 实例,因此 SelectedItem 的相等性检查失败。
标签: wpf data-binding combobox