使用数据绑定到的更新字典内容更新组合框内容
Update Combo Box contents with the updated dictionary contents that it is data binded to
我有一个组合框,它的显示路径和值路径已成功绑定到字典。
唯一的问题是 XAML 直到这些框在上面的 xaml 中布置之后才填充实际字典。
所以组合框不显示任何内容,因为在制作组合框时字典甚至不存在。
有没有办法在主 window 加载后更新组合框,这样我就不必为了让它恢复到原来的样子而对布局进行太多修改在字典对象实例化后放置组合框 xaml 之后想要吗?
我觉得这是最简单的方法。
很高兴看到您正在尝试做的事情的示例,但我会尝试用您提供的内容来回答。
组合框需要知道它绑定到的集合已经更新,并在更新时刷新它的视觉表示。集合本身负责通知绑定到它的控件集合已更改。字典没有这种通知绑定到它们的控件的能力。
您应该考虑使用 ObservableCollection。假设您使用的是视图模型,它看起来像这样:
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<MyComboBoxItem> _myItems;
public ObservableCollection<MyComboBoxItem> MyItems
{
get => _myItems;
set { _myItems = value; OnPropertyChanged(); }
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void InitializeCollection()
{
MyItems = new ObservableCollection<MyComboBoxItem>();
MyItems.Add(new MyComboBoxItem() { Text = "Hello" });
}
}
在您的 XAML 中,您将在绑定中指定 MyItems。 ComboBox 将在创建集合时和集合成员更改时更新。
<ComboBox ItemsSource="{Binding MyItems}"/>
这假定视图的数据上下文已设置为 MyViewModel 的实例。
已更新以支持复合集合绑定
下面是一个使用带有组合框的复合集合的示例。第一,观点。在这里,我创建了一个绑定到复合集合的 ComboBox。我还有一个文本框,显示组合框中的选定项,以及两个列表,显示视图模型上两个 ObservableCollections 的内容。最后有一个按钮,可以将新项目添加到复合视图中的其中一个集合。
<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="450"
Width="800">
<Window.Resources>
<DataTemplate x:Key="ComboBoxItemDataTemplate"
DataType="local:MyComboBoxItem">
<TextBlock Margin="4"
Text="{Binding Text}" />
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Center">
<StackPanel Margin="4"
Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<ComboBox Margin="4"
Width="220"
Height="28"
ItemsSource="{Binding ComboBoxItems}"
SelectedItem="{Binding SelectedComboBoxItem, Mode=TwoWay}"
ItemTemplate="{StaticResource ComboBoxDataTemplate}" />
<TextBlock Margin="4"
Width="220"
Text="{Binding SelectedComboBoxItem.Text}" />
</StackPanel>
<TextBlock Margin="4"
Text="Invariable Items" />
<ListBox Margin="4"
ItemsSource="{Binding InvariableItems}"
ItemTemplate="{StaticResource ComboBoxDataTemplate}" />
<TextBlock Margin="4"
Text="Variable Items" />
<ListBox Margin="4"
ItemsSource="{Binding VariableItems}"
ItemTemplate="{StaticResource ComboBoxDataTemplate}" />
<Button Width="80"
Click="OnAddVariableItem">Add</Button>
</StackPanel>
</Grid>
</Window>
这是视图的隐藏代码。它在构造函数中初始化视图的 DataContext 并具有按钮的单击事件处理程序。
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
var dc = new MyViewModel();
DataContext = dc;
}
private void OnAddVariableItem(object sender, RoutedEventArgs e)
{
if (DataContext is MyViewModel viewModel)
{
viewModel.AddVariableItem();
}
}
}
现在是视图模型。首先,class 包含项目:
public class MyComboBoxItem
{
public string Color { get; set; }
public string Text { get; set; }
}
接下来,视图模型本身。我们定义了两个可观察的集合,一个用于永不改变的事物,一个用于经常改变的事物。然后我们为视图创建一个复合集合。当我们将新项目添加到变量集合时,我们只需重新创建复合集合。
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private ObservableCollection<MyComboBoxItem> _variableItems;
public ObservableCollection<MyComboBoxItem> VariableItems
{
get => _variableItems;
set { _variableItems = value; OnPropertyChanged(); }
}
private ObservableCollection<MyComboBoxItem> _invariableItems;
public ObservableCollection<MyComboBoxItem> InvariableItems
{
get => _invariableItems;
set { _invariableItems = value; OnPropertyChanged(); }
}
private CompositeCollection _comboBoxItems;
public CompositeCollection ComboBoxItems
{
get => _comboBoxItems;
set { _comboBoxItems = value; OnPropertyChanged(); }
}
private MyComboBoxItem _selectedComboBoxItem;
public MyComboBoxItem SelectedComboBoxItem
{
get => _selectedComboBoxItem;
set { _selectedComboBoxItem = value; OnPropertyChanged(); }
}
public MyViewModel()
{
Init();
}
private void Init()
{
InvariableItems = new ObservableCollection<MyComboBoxItem>()
{
new MyComboBoxItem() {Text = "(Select One)"},
new MyComboBoxItem() {Text = "(Default)"},
};
VariableItems = new ObservableCollection<MyComboBoxItem>()
{
new MyComboBoxItem() {Text = "Shoes"},
new MyComboBoxItem() {Text = "Hat"},
new MyComboBoxItem() {Text = "Gloves"}
};
ComboBoxItems = Create(new List<IEnumerable<MyComboBoxItem>>()
{
InvariableItems,
VariableItems
});
SelectedComboBoxItem = InvariableItems[0];
}
private CompositeCollection Create(List<IEnumerable<MyComboBoxItem>> collections)
{
var compColl = new CompositeCollection();
foreach (var coll in collections)
{
var container = new CollectionContainer()
{
Collection = coll
};
compColl.Add(container);
}
return compColl;
}
public void AddVariableItem()
{
VariableItems.Add(new MyComboBoxItem() { Text = "Another item" });
ComboBoxItems = Create(new List<IEnumerable<MyComboBoxItem>>()
{
InvariableItems,
VariableItems
});
}
}
我有一个组合框,它的显示路径和值路径已成功绑定到字典。
唯一的问题是 XAML 直到这些框在上面的 xaml 中布置之后才填充实际字典。
所以组合框不显示任何内容,因为在制作组合框时字典甚至不存在。
有没有办法在主 window 加载后更新组合框,这样我就不必为了让它恢复到原来的样子而对布局进行太多修改在字典对象实例化后放置组合框 xaml 之后想要吗?
我觉得这是最简单的方法。
很高兴看到您正在尝试做的事情的示例,但我会尝试用您提供的内容来回答。
组合框需要知道它绑定到的集合已经更新,并在更新时刷新它的视觉表示。集合本身负责通知绑定到它的控件集合已更改。字典没有这种通知绑定到它们的控件的能力。
您应该考虑使用 ObservableCollection。假设您使用的是视图模型,它看起来像这样:
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<MyComboBoxItem> _myItems;
public ObservableCollection<MyComboBoxItem> MyItems
{
get => _myItems;
set { _myItems = value; OnPropertyChanged(); }
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void InitializeCollection()
{
MyItems = new ObservableCollection<MyComboBoxItem>();
MyItems.Add(new MyComboBoxItem() { Text = "Hello" });
}
}
在您的 XAML 中,您将在绑定中指定 MyItems。 ComboBox 将在创建集合时和集合成员更改时更新。
<ComboBox ItemsSource="{Binding MyItems}"/>
这假定视图的数据上下文已设置为 MyViewModel 的实例。
已更新以支持复合集合绑定
下面是一个使用带有组合框的复合集合的示例。第一,观点。在这里,我创建了一个绑定到复合集合的 ComboBox。我还有一个文本框,显示组合框中的选定项,以及两个列表,显示视图模型上两个 ObservableCollections 的内容。最后有一个按钮,可以将新项目添加到复合视图中的其中一个集合。
<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="450"
Width="800">
<Window.Resources>
<DataTemplate x:Key="ComboBoxItemDataTemplate"
DataType="local:MyComboBoxItem">
<TextBlock Margin="4"
Text="{Binding Text}" />
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Center">
<StackPanel Margin="4"
Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<ComboBox Margin="4"
Width="220"
Height="28"
ItemsSource="{Binding ComboBoxItems}"
SelectedItem="{Binding SelectedComboBoxItem, Mode=TwoWay}"
ItemTemplate="{StaticResource ComboBoxDataTemplate}" />
<TextBlock Margin="4"
Width="220"
Text="{Binding SelectedComboBoxItem.Text}" />
</StackPanel>
<TextBlock Margin="4"
Text="Invariable Items" />
<ListBox Margin="4"
ItemsSource="{Binding InvariableItems}"
ItemTemplate="{StaticResource ComboBoxDataTemplate}" />
<TextBlock Margin="4"
Text="Variable Items" />
<ListBox Margin="4"
ItemsSource="{Binding VariableItems}"
ItemTemplate="{StaticResource ComboBoxDataTemplate}" />
<Button Width="80"
Click="OnAddVariableItem">Add</Button>
</StackPanel>
</Grid>
</Window>
这是视图的隐藏代码。它在构造函数中初始化视图的 DataContext 并具有按钮的单击事件处理程序。
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
var dc = new MyViewModel();
DataContext = dc;
}
private void OnAddVariableItem(object sender, RoutedEventArgs e)
{
if (DataContext is MyViewModel viewModel)
{
viewModel.AddVariableItem();
}
}
}
现在是视图模型。首先,class 包含项目:
public class MyComboBoxItem
{
public string Color { get; set; }
public string Text { get; set; }
}
接下来,视图模型本身。我们定义了两个可观察的集合,一个用于永不改变的事物,一个用于经常改变的事物。然后我们为视图创建一个复合集合。当我们将新项目添加到变量集合时,我们只需重新创建复合集合。
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private ObservableCollection<MyComboBoxItem> _variableItems;
public ObservableCollection<MyComboBoxItem> VariableItems
{
get => _variableItems;
set { _variableItems = value; OnPropertyChanged(); }
}
private ObservableCollection<MyComboBoxItem> _invariableItems;
public ObservableCollection<MyComboBoxItem> InvariableItems
{
get => _invariableItems;
set { _invariableItems = value; OnPropertyChanged(); }
}
private CompositeCollection _comboBoxItems;
public CompositeCollection ComboBoxItems
{
get => _comboBoxItems;
set { _comboBoxItems = value; OnPropertyChanged(); }
}
private MyComboBoxItem _selectedComboBoxItem;
public MyComboBoxItem SelectedComboBoxItem
{
get => _selectedComboBoxItem;
set { _selectedComboBoxItem = value; OnPropertyChanged(); }
}
public MyViewModel()
{
Init();
}
private void Init()
{
InvariableItems = new ObservableCollection<MyComboBoxItem>()
{
new MyComboBoxItem() {Text = "(Select One)"},
new MyComboBoxItem() {Text = "(Default)"},
};
VariableItems = new ObservableCollection<MyComboBoxItem>()
{
new MyComboBoxItem() {Text = "Shoes"},
new MyComboBoxItem() {Text = "Hat"},
new MyComboBoxItem() {Text = "Gloves"}
};
ComboBoxItems = Create(new List<IEnumerable<MyComboBoxItem>>()
{
InvariableItems,
VariableItems
});
SelectedComboBoxItem = InvariableItems[0];
}
private CompositeCollection Create(List<IEnumerable<MyComboBoxItem>> collections)
{
var compColl = new CompositeCollection();
foreach (var coll in collections)
{
var container = new CollectionContainer()
{
Collection = coll
};
compColl.Add(container);
}
return compColl;
}
public void AddVariableItem()
{
VariableItems.Add(new MyComboBoxItem() { Text = "Another item" });
ComboBoxItems = Create(new List<IEnumerable<MyComboBoxItem>>()
{
InvariableItems,
VariableItems
});
}
}