【问题标题】:Bind selected item to view model将所选项目绑定到视图模型
【发布时间】:2016-06-30 09:04:06
【问题描述】:

将 ListBox selectedItem 绑定到我的 ViewModel 需要什么? 视图模型 SelectedClient 始终为空。

通过名为 ClientClickedCommand 的命令成功调用 ClientSelected。但是当我尝试在 ClientSelected 方法中访问视图模型 SelectedClient 时,它的 null 并引发异常。

XAML

<ListBox x:Name="lbSlaves" Width="300" Grid.Row="1"  ItemsSource="{Binding Slaves}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
             SelectedItem="{Binding SelectedClient, Mode=TwoWay}"
             >
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel  />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <CheckBox  IsChecked="{Binding Checked ,Mode=TwoWay}"/>
                    <Button 
                        Command="{Binding  ElementName=MainGrid, Path=DataContext.ClientClickedCommand}"                    
                        >
                        <TextBlock Text="{Binding MachineName, Mode=OneWay}" />
                    </Button>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

VIEVMODEL(绑定到 DataContext)

        private MyClient _selectedClient;
    public MyClient SelectedClient
    {
        get {
            return _selectedClient;
        }
        set
        {
            if (value != _selectedClient)
            {
                _selectedClient = value;
                NotifyPropertyChanged("SelectedClient");
            }
        }
    }

    public string _infoText;
    public string InfoText { 
        get {
        return _infoText;
    }
        set {
            if (value != _infoText)
            {
                _infoText = value;
                NotifyPropertyChanged("InfoText");
            }
        }
    }

    private void ClientSelected()
    {
        var message = " - " + SelectedClient.MachineName + " was clicked";
        InfoText += message;

    }

ClientClickedCommand = new Command(ClientSelected,  ()=>  true); 



  public ICommand ClientClickedCommand
        {
            get;
            set;
        }

更新:我现在尝试像这样通过 CommandParameter 绑定 SelectedClient

  <ListBox x:Name="lbSlaves" Width="600" Grid.Row="1" 
             ItemsSource="{Binding Slaves}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel  />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <WrapPanel Orientation="Horizontal" Width="150" Height="60">
                    <CheckBox  IsChecked="{Binding Checked ,Mode=TwoWay}"/>
                    <TextBlock Text="{Binding MachineName, Mode=OneWay}" />
                    <Button 
                        Content="Do something"  
                        Command="{Binding  ElementName=MainGrid, Path=DataContext.ClientClickedCommand}" 
                        CommandParameter="{Binding ElementName=MainGrid, Path=DataContext.SelectedClient, Mode=TwoWay}" />

                    <Button Content="Do another thing>" />

                </WrapPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

【问题讨论】:

  • 你是先选择项目然后点击按钮,还是直接点击按钮?
  • 我只是单击该项目。我如何选择它们?选择和点击有什么区别?
  • 如果你直接点击DataTemplate中定义的按钮而不选择包含这个按钮的项目,你可能需要一个CommandParameter
  • 好的,谢谢。所以我再问一次。选择项目和单击按钮内的按钮有什么区别。我想我不明白 WPF 是如何处理这个问题的。
  • 在某些时候需要处理鼠标点击。如果按钮处理它,则底层控件不会。

标签: c# .net wpf xaml


【解决方案1】:

按钮可能会吞下鼠标单击,但除此之外,您的 SelectedClient 属性所在的位置尚不清楚。它似乎在 MyClient 类中,而它应该在 Slaves 的同一级别。

编辑: 如果您想保留自己的按钮,请使用 CommandParameter,如下所示:

Command="{Binding  ElementName=MainGrid, Path=DataContext.ClientClickedCommand}" CommandParameter="{Binding}"

我不确定new Command (...) 的工作原理,但有些命令需要参数,所以下一部分应该是这样的:

private void ClientSelected(MyClient client)
{
    SelectedClient = client;
    var message = " - " + SelectedClient.MachineName + " was clicked";
    InfoText += message;

}

【讨论】:

  • SelectedClient 在 MyViewModel 和 Slaves 中。所以他们处于同一水平。
  • MyClient 是否引用了MyViewModel?如果是这样,您可以使用按钮并在其命令中,将其“父”MyViewModelSelectedClient 设置为自身。
  • 不,不是。 MyClient 不知道它所在的容器。肯定有其他方法。
  • @Lautaro 我认为问题在于按钮正在消耗鼠标单击事件。默认情况下,当您单击它时,您的 listboxitem 应该突出显示,它没有突出显示对吗?
  • @Lautaro 在 SelectedClient 的 setter 或命令中处理它,不要同时进行
【解决方案2】:

大多数人已经告诉过您这个问题 - 您的 ListViewItem 内的按钮正在消耗您的点击事件。当您将命令分配给按钮时,WPF 将在后台订阅按钮的单击事件。处理点击事件的默认行为是设置e.Handled = true;,这会导致其他由鼠标单击产生的事件停止工作。

您是否对SelectedClient 和命令分开使用还不太清楚。如果你只想知道用户点击了那个 ListViewItem,你可以不使用命令。

public MyClient SelectedClient
{
    get
    {
        return _selectedClient;
    }
    set
    {
        if (value != _selectedClient)
        {
            _selectedClient = value;
            ClientSelected();
            NotifyPropertyChanged("SelectedClient");
        }
    }
}

如果选择 ListViewItem 与按钮的目的不同,那么您需要考虑为什么每个 ListViewItem 需要一个按钮。从逻辑上讲,如果所有项目都需要做类似性质的事情,您可以将按钮放在 ListView 之外。这样,按钮就不会弄乱您的 ListView。

【讨论】:

  • 这样就解决了。谢谢!但是我需要弄清楚如何在每个项目中包含按钮,因为我必须扩展功能。每个客户端需要三个按钮来触发使用该特定客户端的不同方法。
  • @Lautaro 在我看来,您不需要 ListView。你可以简单地使用ItemsControl
  • 实际上现在我意识到这种方式只能让我点击一次,然后我必须取消选择它。我想我应该看看 ItemsControl。
猜你喜欢
  • 1970-01-01
  • 2013-04-28
  • 1970-01-01
  • 2018-07-27
  • 1970-01-01
  • 2011-08-10
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
相关资源
最近更新 更多