MVVM Listbox DataTemplate SelectedItem

时间:2011-11-25 01:43:43

标签: c# wpf mvvm

我正在使用带有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="{Binding DataContext.CommandName} RelativeSource={RelativeSource FindAncestor, ListBox, 1}用于命令绑定。我不完全理解它在做什么,但我确实知道当我直接绑定到CommandName时命令没有被触发。

2 个答案:

答案 0 :(得分:3)

您正在使用MVVM ....所以非常简单的解决方法是将SelectedItem作为参数传递给Both按钮的命令,然后使用参数的值设置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项目,点击按钮....

应该这样做......:)

答案 1 :(得分:2)

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

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

该行为执行一项已知的操作,并且仅通过控件(XAML)的视觉样式设置,该控件知道该按钮位于ListBoxItem内。我认为这可以保持M-V-VM的关注点分离。

如果您需要帮助撰写行为,请与我们联系。