1

我以编程方式创建了一个类(我称之为 ViewGrid),以便我将它的一个实例用作我的 ListBox 控件的 ItemTemplate;当然,这是我的 listboxitem 数据模板....

此外,在我的 ViewGrid 类中,我有一个名为IsChecked的依赖项属性,我希望它与 ListBoxItem 的 IsSelected 属性保持同步。我注意到在 SL 中没有像 WPF 中那样对绑定的 relativesource-findancestor-ancestortype 支持,但我仍然需要找到一种方法来使我的IsChecked属性与我的 ListBox 控件内部生成的 ListBoxItem 的 IsSelected 属性保持同步。你能帮我吗?

4

2 回答 2

0

下面是在 XAML 中定义的 ListBox,它使用每个 LitBoxItem 的 IsSelected 属性在选中时显示或隐藏按钮。您只需为您在代码中创建的 ListBoxItems 复制该绑定方法。要么,要么使用适当的 ListBoxItem XAML 创建一个 UserControl,然后将这些 UserControls 的实例插入到您的 ListBox 中。

<ListBox>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid Width="200" Height="120">
                <StackPanel Margin="5">
                    <TextBlock Text="{Binding Name, Mode=OneWay}" />
                    <StackPanel Visibility="{Binding IsSelected, Mode=OneWay, Converter={StaticResource BoolToVisible}}">
                        <Button Content="Show Details" Click="OnDetailsClick" Tag="{Binding}" />
                    </StackPanel>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

祝你好运,

吉姆·麦柯迪

面对面软件阴阳钱

于 2010-02-03T17:33:38.233 回答
0

更新:我重新审视了这个并找到了一个更好的解决方案。我原来的那个还在下面,但我最终解决这个问题的方法是通过在 ControlTemplate 中使用 ViewGrid 而不是 DataTemplate。然后可以使用RelativeSource TemplatedParent 绑定绑定到ListBox 的IsSelected 属性。因此,将以下内容添加到列表框或页面或用户控件的资源中:

<Style TargetType="ListBoxItem">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBoxItem">
                <StackPanel>
                    <ViewGrid IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"/>​
                    <!-- other controls may go here -->
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

原来的:

所以七年后,你几乎肯定不再需要这个问题的答案了……然而,我最近花了一个上午的时间来解决这个问题,并认为我会给出我的解决方案,以防万一出现类似的不幸事件。

首先,任何使用 Silverlight 5 的人都很幸运,因为 AncestorType 现在显然可用于 RelativeSource,让您可以直接绑定到 ListBoxItem 的 IsSelected 属性。对于我们这些坚持 4 或以下的人来说,我想出的唯一真正的解决方法是通过使用背后代码中的事件来“伪造”绑定。

为此,假设您的 YourView XAML 带有一个名为“lbYourListBox”的 ListBox,它的 ItemsSource 和 SelectedItem 属性绑定到 YourViewModel 类的适当属性,以及其 ItemTemplate 中的 ViewGrid,其 IsChecked 属性未绑定到任何东西。然后,在文件后面的代码中,按如下方式连接事件:

public YourView()
    {
        InitializeComponent();
        this.Loaded += (sender, e) =>
        {
            ((YourViewModel)this.DataContext).PropertyChanged += vm_PropertyChanged;
            UpdateViewGrids();
        };

    }

    // this part propagates changes from the view to the view model
    private void viewGrid_Checked(object sender, RoutedEventArgs e)
    {
        var selectedVM = ((ViewGrid)sender).DataContext as SourceItemType;
        ((YourViewModel)this.DataContext).SelectedViewGridItem = selectedVM;
    }

    private void vm_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (string.Equals(e.PropertyName, "SelectedViewGridItem"))
        {
            UpdateViewGrids();
        }
    }

    // this part propagates changes from the view model to the view
    private void UpdateViewGrids()
    {
        var viewGrids = this.lbYourListBox.GetVisualDescendants().OfType<ViewGrid>();
        var selectedVM = ((YourViewModel)this.DataContext).SelectedViewGridItem;
        foreach (var grid in viewGrids)
        {
            grid.IsChecked = selectedVM == grid.DataContext;
        }
    }​

viewGrid_Checked 事件处理程序应连接到 ItemTemplate 中视图网格的 Checked 事件。GetVisualDescendants() 方法来自 Silverlight 工具包。

重要警告:

  • ViewGrid.Checked 事件不应触发,除非是 unchecked->checked 转换,并且一次只能选择一个视图网格。如果这两件事不正确,则必须进行适当的编辑以确保此代码不会导致无限的事件驱动循环。(当然,如果您不需要双向绑定,则只需要其中一个事件处理程序,而事件 ping-pong 不是问题。)
  • 我为在 XAML 中设置了数据上下文的用户控件编写了这个,这就是为什么视图模型的 PropertyChanged 事件的事件处理程序仅在视图加载后分配的原因。根据您的视图和视图模型相互绑定的方式和时间,您可能必须更早/更晚/不同地分配它。
  • 如果视图网格不可见,这将不起作用,GetVisualDescendants 似乎忽略了隐藏/折叠的控件。
于 2017-01-27T20:51:30.557 回答