Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF列表框选择已更改的MVVM_C#_Wpf_Mvvm - Fatal编程技术网

C# WPF列表框选择已更改的MVVM

C# WPF列表框选择已更改的MVVM,c#,wpf,mvvm,C#,Wpf,Mvvm,我的WPF应用程序中有一个列表框。我知道如何使用selectionchanged事件。然而,我试图遵循MVVM设计。然而,我不知道如何做到这一点 我已经做了一个按钮,但不确定我是否可以做同样的事情 <Button Grid.Column="0" Name="buttImport" Content="Import File" Command="{Binding CommandButtImport}" Style="{StaticResource ButtonTe

我的WPF应用程序中有一个列表框。我知道如何使用selectionchanged事件。然而,我试图遵循MVVM设计。然而,我不知道如何做到这一点

我已经做了一个按钮,但不确定我是否可以做同样的事情

<Button Grid.Column="0" Name="buttImport" 
    Content="Import File" 
    Command="{Binding CommandButtImport}" 
    Style="{StaticResource ButtonTemplate}"/>
编辑请忽略上面的代码

<DataGrid Grid.Row="1" Grid.Column="0" 
     ItemsSource="{Binding SelectedItem.DuplicateSecurities, ElementName=dataGridOrders}" 
     SelectedItem="{Binding SelectedItem.Security, ElementName=dataGridOrders}"> 
我已经更改了我的代码,因此在我当前拥有的代码下面重新发布。我有一个奇怪的问题。XAML-Main代码包含我的datagrid的代码。App-XAML下面的块包含了我大部分应用程序的样式,但只是一个snipet

代码行添加在XAML-Main代码中我的datagrid下面,用于测试目的

<ListBox ItemsSource="{Binding SelectedItem.DuplicateSecurities, ElementName=dataGridOrders}" 
 SelectedItem="{Binding SelectedItem.Security, ElementName=dataGridOrders}"/>
包含其他类的OrderBlocks类

 public class OrderBlocks : INotifyPropertyChanged
{
 private List<Order> _orders;
    [XmlElement("tF_Transactions")]
    public List<Order> Orders { get { return _orders; } set { _orders = value; OnPropertyChanged("Orders"); } }
}
编辑-我的代码现在可以工作了请查看下面适合我的代码片段

<DataGrid Grid.Row="1" Grid.Column="0" 
     ItemsSource="{Binding SelectedItem.DuplicateSecurities, ElementName=dataGridOrders}" 
     SelectedItem="{Binding SelectedItem.Security, ElementName=dataGridOrders}"> 

在ViewModel中将ListBox
SelectionChanged
事件绑定到命令的示例

<ListBox x:Name="myListBox" ItemsSource="{Binding SomeCollection}">
   <ie:Interaction.Triggers>
      <ie:EventTrigger EventName="SelectionChanged">
        <ie:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}"  CommandParameter="{Binding ElementName=myListBox, Path=SelectedItem}"/>
    </ie:EventTrigger>
  </ie:Interaction.Triggers>
</ListBox >
这个特定的示例使用Prism MVVM框架,但是您也可以将相同的思想应用到您正在使用的任何其他MVVM框架中


希望这对使用MVVM的
SelectionChanged
非常简单有帮助:

一种方法是绑定到
列表框
SelectedIndex
属性,并在VM的属性设置器中相应地执行操作,就像在属性更改时触发一样

例如:

在本例中,只要选定索引发生更改,该项的值就会增加一

主要是:

public int SelectedIndex {
  get {
    return _selectedIndex;
  }

  set {
    if (_selectedIndex == value) {
      return;
    }

    // At this point _selectedIndex is the old selected item's index

    _selectedIndex = value;

    // At this point _selectedIndex is the new selected item's index

    RaisePropertyChanged(() => SelectedIndex);
  }
}
xaml只是:

<ListBox ItemsSource="{Binding Items}" SelectedIndex="{Binding SelectedIndex}" />


Items
是我们绑定到的项的集合。

问题是……你能发布你尝试过的内容和这些尝试的结果吗?我上面发布的示例适用于按钮,但我想知道当选择更改时如何对列表框执行此操作。对于MVVM,将
ListBox
SelectedItem
SelectedIndex
属性绑定到VM,并在属性的setter中执行您需要执行的操作,因为当
ListBox
中的选择相应更改时,它会触发。这就是你的问题所在吗?我没有任何结果,因为我不确定该怎么办。我刚刚在互联网上搜索,没有任何乐趣绑定
SelectedIndex
对我来说似乎是个坏主意。。。如何获得所选内容所代表的实际项目?此外,这将意味着您必须实现所有依赖于setter中新选定项的代码(而不是对子方法的划分)。另一件事是,这将允许直接从
ViewModel
更改选择,而不仅仅是UI,如果应用程序没有这样的用途,这是您不想要的-case@Omribitan
Items[SelectedIndex]
我的观点是,您不希望在
视图模型的整个生命周期内保留该选择项的实例,而您只在实际选择发生更改时才需要它。@Omribitan抱歉,在此您不能同意。如果您不想在setter中执行此操作,请将其分派回同一线程或安装INPC watcher并在那里执行相应的操作
这将允许直接从ViewModel而不仅仅是UI更改选择,这是您不想要的,
err what?是虚拟机更改了从虚拟机中选择的
索引
,这是完全有效的设计。在某些情况下,您可能希望将索引设置为-1以删除选择和数百个其他用例。@Omribitan VM通常与视图具有11关系。只要让虚拟机做它想做的“管理相应的视图”。这是WPF。你可以想出10种方法来解决这个问题。我唯一不同意的是“将SelectedIndex绑定到VM是错误的”。选择您喜欢的任何方法:如果任何人在使用此答案中提供的解决方案时出现错误,请参考下面我的答案:您希望顶部的以下命名空间使用“ie:”
xmlns:ie=“clr namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity”
谢谢,这有助于我上路。我只想提一下。您需要将System.Windows.Interactive添加到项目的引用中。对于那些使用常见的RelayCommand的用户,只需像常规命令一样将其连接起来,就可以在参数中获得所选对象。谢谢,这是一个非常好的解决方案。。。我补充说,如果您使用“caliburn.micro”,您应该使用“RelayCommand”而不是“DelegateCommand”,它将在fin中工作。这种解决方案是胡说八道。处理事件不会违反MVVM。MVVm并不意味着对所有事情都使用
ICommand
(强制)。这是一篇老文章,但我希望你现在更了解它。您可以始终绑定到
SelectedItem
r
SelectedIndex
以触发视图模型中的操作。
 public class Security : INotifyPropertyChanged
 {
    private string _id;
    public string ID
    {
        get
        {
            return _id;
        }
        set
        {
            _id = value;
            OnPropertyChanged("ID");
        }
    }

    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
            OnPropertyChanged("Name");
        }
    }

    public Security() { }

    public Security(string newID, string newName)
    {
        ID = newID;
        Name = newName;
    }
<DataGrid Grid.Row="1" Grid.Column="0" 
     ItemsSource="{Binding SelectedItem.DuplicateSecurities, ElementName=dataGridOrders}" 
     SelectedItem="{Binding SelectedItem.Security, ElementName=dataGridOrders}"> 
<ListBox x:Name="myListBox" ItemsSource="{Binding SomeCollection}">
   <ie:Interaction.Triggers>
      <ie:EventTrigger EventName="SelectionChanged">
        <ie:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}"  CommandParameter="{Binding ElementName=myListBox, Path=SelectedItem}"/>
    </ie:EventTrigger>
  </ie:Interaction.Triggers>
</ListBox >
public class myViewModel
{

    public myViewModel()
    {
        SelectedItemChangedCommand = new DelegateCommand<object>((selectedItem) => 
        {
             // Logic goes here
        });
    }

    public List<SomeData> SomeCollection { get; set; }

    public DelegateCommand<object> SelectedItemChangedCommand { get; set; }
}
public int SelectedIndex {
  get {
    return _selectedIndex;
  }

  set {
    if (_selectedIndex == value) {
      return;
    }

    // At this point _selectedIndex is the old selected item's index

    _selectedIndex = value;

    // At this point _selectedIndex is the new selected item's index

    RaisePropertyChanged(() => SelectedIndex);
  }
}
<ListBox ItemsSource="{Binding Items}" SelectedIndex="{Binding SelectedIndex}" />