【问题标题】:MVVM Listbox DataTemplate SelectedItemMVVM 列表框数据模板 SelectedItem
【发布时间】:2011-11-25 01:43:43
【问题描述】:

我正在使用带有DataTemplate 的 ListBox,如下所示(xaml 简化并且变量名称已更改)。

<ListBox ItemsSource="{Binding Path=ObservCollectionItems}"
         SelectedItem="{Binding Path=SelectedItemVar, Mode=TwoWay}">
         <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding SomeVar}" />
                    <Border>
                        <StackPanel>
                            <Button Content="String1"
                                    Command="{Binding DataContext.Command1}
                                    RelativeSource={RelativeSource FindAncestor, ListBox, 1}}" />
                            <Button Content="String2" 
                                    Command="{Binding DataContext.Command2}
                                    RelativeSource={RelativeSource FindAncestor, ListBox, 1}}" />
                        </StackPanel>
                    </Border>
                </StackPanel>
            </DataTemplate>
         <ListBox.ItemTemplate>
 </ListBox>

当我单击其中一个按钮时,我需要更新 SelectedItemVar(依赖属性)。然后将 SelectedItemVar 用于相应按钮的命令。当我单击TextBlockBorder 时,SelectedItemVar 会更新,但当我单击任一按钮时不会更新。我找到了这个问题的非 MVVM 解决方案here。我不想在文件后面添加代码来解决这个问题,就像他们在链接中所做的那样。

是否有可以在 XAML 中完成的干净解决方案。除了非 MVVM 解决方案之外,我还没有发现有人遇到这个问题。我会认为这是相当普遍的。

最后,我为 Command 绑定找到了这个 Command="{Binding DataContext.CommandName} RelativeSource={RelativeSource FindAncestor, ListBox, 1}。我不完全理解它在做什么,但我知道当我直接绑定到 CommandName 时该命令没有触发。

【问题讨论】:

  • 确保将 SelectedItem 绑定放在 ItemsSource 绑定之前。否则,当 ItemsSource 取消绑定时,SelectedItem 将获得 null 的 setter 调用。
  • 我将确保按该顺序设置绑定。谢谢指点。

标签: c# wpf mvvm


【解决方案1】:

您正在使用 MVVM .... 非常简单的解决方案是将 SelectedItem 作为参数传递给两个按钮的命令,然后使用参数的值设置 SelectedItem .....

代码

public class YourViewmodel
{
     //Other Variables
     
     
     public YourViewModelCtor()
     {
        Command1= new RelayCommand(Command1Func);
     }
     
     Public SelectedVar
     {
             get {return value;}
             Set { selectedVar=value;
                       OnPropertyChanged("SelectedVar");
              }
     }

     //Other Properties


     void Command1Func(object obj)
     {
              SelectedVar= obj as <Your Desired Type>;

              //Do your thing with SelectedVar ... Do the same for Command2
     }
}

Xaml 中所需的更改

<StackPanel>
    <Button Command="{Binding DataContext.Command1}" CommandParameter="{Binding}"
            Content="String1" />
    <Button Command="{Binding DataContext.Command2}" CommandParameter="{Binding}"
            Content="String2" />
</StackPanel>

这将为您提供单击按钮的当前 ListBox 项...。​​

应该这样做……:)

【讨论】:

  • 这个解决方案效果很好。这是我所希望的简单的 XAML 解决方案。你能告诉我CommandParameter Binding 的作用吗?再次感谢!
  • @StinkerPeter CommandParameter 将参数(在本例中为单击的当前行)发送到名为 ("obj") 的函数的参数,以便您可以将一些值从 XAML 发送到 ViewModel 并在此处进行相应处理。
【解决方案2】:

您需要一些代码来处理您想要的视觉行为,但您不必将其放入您的视图模型或控件代码隐藏中。

我会编写一个 Behavior(称为 SelectListBoxItemWhenClickedBehavior 之类的东西),当单击按钮时,它会在可视树中查找 ListBoxItem(使用 VisualTreeHelper)。然后它可以设置 ListBoxItem.IsSelected = true。

该行为做了一件已知的事情,它仅由控件的视觉样式 (XAML) 设置,该控件知道按钮位于 ListBoxItem 内。我认为这使 M-V-VM 的关注点分离保持在适当的位置。

如果您在编写行为方面需要帮助,请告诉我。

【讨论】:

  • 我会试一试,如果需要帮助,我会回来。我以前从未写过,但我不反对在寻求帮助之前尝试!再次感谢。
  • 杰夫,感谢您的帮助。我没有时间尝试您的解决方案。我选择了标记答案,因为它易于实施。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-03
  • 2011-09-27
  • 2013-07-14
相关资源
最近更新 更多