我有一个简单的WPF页面,其中包含一个包含ListBox的自定义控件(BrowsingPanel),另一个控件(ItemDataSheet)显示与在ListBox中选择的元素相关的数据。当我单击ListBox中的某个项目时,会向BrowsingPanelViewModel发送一个命令,该命令会发送一条消息。 ItemDataSheetViewModel接收消息,更新ItemDataSheet视图。
这是我的BrowsingPanel.xaml:
<Grid>
<ListBox x:Name="itemsList"
ItemsSource="{Binding MyItems}"
Background="DarkGray">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}"
CommandParameter="{Binding ElementName=itemsList, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
</Grid>
它很好用,除了我希望默认选择第一个ListBox项。为此,我尝试了两件事: 首先,我尝试选择BrowsingPanelViewModel构造函数中的第一项,如下所示。
public RelayCommand<MyItem> SelectedItemChangedCommand { get; private set; }
public BrowsingPanelViewModel()
{
SelectedItemChangedCommand = new RelayCommand<MyItem>(SelectedItemChanged);
MyItems = new ObservableCollection<MyItem>();
MyItems.Add(ParsetemFromResourceName("Resources/toto.txt"));
MyItems.Add(ParseItemFromResourceName("Resources/tata.txt"));
MyItems.Add(ParseItemFromResourceName("Resources/titi.txt"));
//Select the first item if there's one
if (MyItems.Any())
SelectedItemChanged(MyItems.First());
}
void SelectedItemChanged(MyItem selectedItem)
{
Messenger.Default.Send(new NotificationMessage<MyItem>(selectedItem, Notification.SelectedMyChanged));
}
这很好用,ItemDataSheetViewModel显示与此项目对应的数据,但在ListBox中没有(视觉上)选择该项目。
然后,我尝试从BrowsingPanel视图中选择第一项。在后面的代码中,我有一个itemsList_Loaded的处理程序,如下所示:
private void itemsList_Loaded(object sender, RoutedEventArgs e)
{
//Select the first item by default
itemsList.Focus();
if (itemsList.Items.Count > 0)
itemsList.SelectedItem = itemsList.Items[0];
}
这就是我得到奇怪行为的地方。这会在ListBox中正确选择项目,但不会触发SelectedItemChanged命令。我不明白为什么。
有趣的是,如果我用一个SelectionChanged事件替换我的EventTrigger,我将其置于后面的代码中,如下所示,则调用回调函数。
<Grid>
<ListBox x:Name="itemsList"
ItemsSource="{Binding MyItems}"
Background="DarkGray"
Loaded="itemsList_Loaded"
SelectionChanged="itemsList_SelectionChanged"> <!-- This is called when changing SelectedItem in the Loaded -->
</ListBox>
</Grid>
显然,通过组合我提到的2个解决方案,它可以工作:视图模型构造函数中的位在ItemDataSheet视图中显示相应的数据,而itemsList_Loaded中的位可视地选择List中的项目。但我发现这不是很优雅......
在我看来,以编程方式更改ListBox的SelectedIndex应该触发SelectionChanged命令,但它没有。
任何帮助将不胜感激!
答案 0 :(得分:3)
请记住,这是单个选择列表框的解决方案。
你真的不需要大部分代码。
它可以像只需要列表框中的SelectedValue属性一样简单:
<Grid>
<ListBox x:Name="itemsList"
ItemsSource="{Binding MyItems}"
SelectedValue="{Binding Path=MySelectedItem, Mode=TwoWay}"
Background="DarkGray">
</ListBox>
</Grid>
然后可以使用MySelectedItem属性将其绑定到BrowsingPanelViewModel:
private MyItem m_MySelectedItem;
public MyItem MySelectedItem
{
get
{
return m_MySelectedItem;
}
set
{
m_MySelectedItem = value;
NotifyPropertyChanged("MySelectedItem");
}
}
设置器中的notifypropertychanged是关键所在。
然后,您可以通过分配此属性从viewmodel中选择第一个列表项。
您还需要在ListBox范围内为MyItem对象创建一个DataTemplate,它可以简单如下:
<DataTemplate DataType={x:Type MyItem}>
<Textblock Text="{Binding Path=MyItemDescription"/>
</DataTemplate>
或者其他什么。