C# WPF ListBox绑定最初可以工作,但之后不能工作
基本问题=>选择其他组合框值时,我的列表框不会更新 我正在按照MVVM模式制作一个WPF应用程序(或者至少尝试这样做)。我有一个基于当前选择的服务器获取的服务器列表 “申请”。服务器列表放在一个列表框中,当我通过下拉菜单更改“应用程序”时,我希望列表框与新服务器一起更新 “Current:”值将根据所做的选择进行更改(以便绑定至少起作用)。我有一个ServerListViewModel类,它实现了INotifyPropertyChanged。这里有一个片段 ServerListViewModel(代码片段) 设置viewmodel.cs 下拉菜单位于设置选项卡上,而服务器列表有自己的选项卡。这些选项卡有自己的视图模型 以下是此视图模型的一个片段:C# WPF ListBox绑定最初可以工作,但之后不能工作,c#,wpf,xaml,mvvm,data-binding,C#,Wpf,Xaml,Mvvm,Data Binding,基本问题=>选择其他组合框值时,我的列表框不会更新 我正在按照MVVM模式制作一个WPF应用程序(或者至少尝试这样做)。我有一个基于当前选择的服务器获取的服务器列表 “申请”。服务器列表放在一个列表框中,当我通过下拉菜单更改“应用程序”时,我希望列表框与新服务器一起更新 “Current:”值将根据所做的选择进行更改(以便绑定至少起作用)。我有一个ServerListViewModel类,它实现了INotifyPropertyChanged。这里有一个片段 ServerListViewMode
public ComboBoxItem CurrentApplication
{
get { return _settingsModel.CurrentApplication; }
set {
SetCurrentApplication(value);
}
}
private void SetCurrentApplication(ComboBoxItem value)
{
if (ReferenceEquals(_settingsModel.CurrentApplication, value)) return;
_savedSettings = MySettings.Load();
if (value.Content == null)
{
_settingsModel.CurrentApplication =
new ComboBoxItem { Content = _savedSettings.CurrentApplication };
}
else
{
_settingsModel.CurrentApplication = value;
_savedSettings.CurrentApplication = (string)value.Content;
_savedSettings.Save();
ServerListViewModel.Instance.ServerList = ConfigUtility.GetServers();
}
InvokePropertyChanged("CurrentApplication");
}
我还有一个MySettings对象,它将值保存到JSON文件中,以便保存活动的“应用程序”b/w会话
XAML
<TabControl DockPanel.Dock="Bottom" HorizontalAlignment="Stretch" Height="Auto" TabStripPlacement="Bottom">
<!-- Server List -->
<TabItem Name="ServerListTab" Header="Server List">
<TabItem.DataContext>
<viewModel:ServerListViewModel />
</TabItem.DataContext>
<ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
ItemsSource="{Binding ServerList, UpdateSourceTrigger=PropertyChanged}" IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedServer}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="FontSize" Value="14"></Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</TabItem>
<!-- Settings -->
<TabItem Name="SettingsTab" Header="Settings">
<TabItem.DataContext>
<viewModel:SettingsViewModel />
</TabItem.DataContext>
<StackPanel>
<TextBlock FontWeight="Bold">Application</TextBlock>
<WrapPanel>
<TextBlock>Current:</TextBlock>
<TextBlock Text="{Binding CurrentApplication.Content}"></TextBlock>
</WrapPanel>
<TextBlock>Select</TextBlock>
<ComboBox Name="TheComboBox" SelectedItem="{Binding CurrentApplication}">
<ComboBoxItem>NetWebServer</ComboBoxItem>
<ComboBoxItem>NetSearchService</ComboBoxItem>
<ComboBoxItem>NetInterface</ComboBoxItem>
</ComboBox>
<TextBlock FontWeight="Bold">Service</TextBlock>
<WrapPanel>
<TextBlock>Current:</TextBlock>
<TextBlock></TextBlock>
</WrapPanel>
<TextBlock>Select</TextBlock>
<ComboBox></ComboBox>
<CheckBox>
Perfomance mode
</CheckBox>
<CheckBox>
Show live servers
</CheckBox>
<CheckBox>
Show test servers
</CheckBox>
<CheckBox>
Show only parameters with IP's
</CheckBox>
</StackPanel>
</TabItem>
</TabControl>
应用
当前:
挑选
网络服务器
NetSearchService
网络接口
服务
当前:
挑选
性能模式
显示实时服务器
显示测试服务器
仅显示具有IP的参数
我还没有把它们分成不同的视图。问题在于,它们不是不同文件中的独立用户控件,具有自己的视图模型?但是,我已将不同的选项卡项设置为相应的视图模型
结论/问题
如何获得它,以便通过在组合框中选择一个新项目,它也会更新服务器列表?通过调试我的代码,似乎每件事都是一行一行地工作的,所以无论如何列表框不能被通知任何更改?如果我在选择其他“应用程序”的情况下关闭应用程序,然后将其重新打开,则它会正确地使用保存的设置以新值填充列表框。但是,当应用程序打开时,我无法更改列表框。有什么想法吗?如果我什么都做了,SetCurrentApplication()将需要刷新服务器列表并弹出一个INotifyChanged事件。在XAML中,您创建了一个ServerListViewModel对象,该对象被设置为TabItem的DataContext 但是,在方法SetCurrentApplication中,您将更新另一个ServerListViewModel对象的ServerList属性(该静态属性的初始值设定项创建了该对象)。在UI中看不到任何更改,因为用作DataContext的ServerListViewModel对象实际上未被触及 只需使用静态ServerListViewModel.Instance属性中的ServerListViewModel对象作为DataContext:
<TabItem
DataContext="{x:Static viewModel:ServerListViewModel.Instance}"
Name="SettingsTab" Header="Settings"
>
...
...
现在,在SetCurrentApplication方法中更新ServerListViewModel.Instance.ServerList应该会导致数据绑定更新
另一个更干净的替代方法是避免静态实例属性,并在视图模型之间使用某种消息传递。SetCurrentApplication方法可能会发送一条消息,要求更新服务器列表。ServerListViewModel类将处理该消息并执行更新服务器列表的实际工作。MVVM库(如MVVM Light和其他)提供了Messenger组件,可以实现这一点。如果您使用的是WPF,您可能应该使用ObservableCollections而不是BindingList我正在访问SettingsViewModel作为SettingsTab的DataContext,所以我不能像上面所示那样将DataContext设置为ServerListViewModel静态实例,对吗?您是否建议我放弃这个想法,转而采用您提到的消息传递实现?从技术上讲,您可以使用ServerListViewModel的单个静态实例作为设置Stab的DataContext。这对于您的应用程序是否有意义,以及这需要多少代码更改,我不知道。但是,是的,正如我所说的,我倾向于消息传递实现。现在,SettingsViewModel和ServerListViewModel之间有一个硬依赖关系,这是令人头痛的原因。你可能会同意,我们在这里工作的场景仍然相当简单。(续)想象一下,您的软件变得越来越复杂,视图模型之间的硬依赖性可能会带来很多麻烦。使用消息传递将消除这些硬依赖并避免这些头痛:)也就是说,并不是所有虚拟机之间的硬依赖都是有害的。如果viewmodels具有明显的父子关系或类似关系(如一个VM生成/提供/聚合另一个VM),那么硬依赖当然不是问题。。。
<TabControl DockPanel.Dock="Bottom" HorizontalAlignment="Stretch" Height="Auto" TabStripPlacement="Bottom">
<!-- Server List -->
<TabItem Name="ServerListTab" Header="Server List">
<TabItem.DataContext>
<viewModel:ServerListViewModel />
</TabItem.DataContext>
<ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
ItemsSource="{Binding ServerList, UpdateSourceTrigger=PropertyChanged}" IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedServer}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="FontSize" Value="14"></Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</TabItem>
<!-- Settings -->
<TabItem Name="SettingsTab" Header="Settings">
<TabItem.DataContext>
<viewModel:SettingsViewModel />
</TabItem.DataContext>
<StackPanel>
<TextBlock FontWeight="Bold">Application</TextBlock>
<WrapPanel>
<TextBlock>Current:</TextBlock>
<TextBlock Text="{Binding CurrentApplication.Content}"></TextBlock>
</WrapPanel>
<TextBlock>Select</TextBlock>
<ComboBox Name="TheComboBox" SelectedItem="{Binding CurrentApplication}">
<ComboBoxItem>NetWebServer</ComboBoxItem>
<ComboBoxItem>NetSearchService</ComboBoxItem>
<ComboBoxItem>NetInterface</ComboBoxItem>
</ComboBox>
<TextBlock FontWeight="Bold">Service</TextBlock>
<WrapPanel>
<TextBlock>Current:</TextBlock>
<TextBlock></TextBlock>
</WrapPanel>
<TextBlock>Select</TextBlock>
<ComboBox></ComboBox>
<CheckBox>
Perfomance mode
</CheckBox>
<CheckBox>
Show live servers
</CheckBox>
<CheckBox>
Show test servers
</CheckBox>
<CheckBox>
Show only parameters with IP's
</CheckBox>
</StackPanel>
</TabItem>
</TabControl>
<TabItem
DataContext="{x:Static viewModel:ServerListViewModel.Instance}"
Name="SettingsTab" Header="Settings"
>
...