Silverlight relativebinding ItemTemplate ListboxItem - Listbox

时间:2010-02-02 11:49:47

标签: silverlight data-binding listbox listboxitem

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

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

2 个答案:

答案 0 :(得分:0)

这是在XAML中定义的ListBox,它使用每个LitBoxItem的IsSelected属性在选中时显示或隐藏按钮。您只需要为在代码中创建的ListBoxItem复制Binding方法。或者,或者使用适当的ListBoxItem XAML创建UserControl,并将这些UserControl的实例插入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>
祝你好运,

Jim McCurdy

Face To Face SoftwareYinYangMoney

答案 1 :(得分:0)

更新:我重新审视了这一点,并找到了一个更好的解决方案。我原来的一个仍在下面,但我实际上最终解决这个问题的方法是在ControlTemplate而不是DataTemplate中使用ViewGrid。然后,您可以使用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>

ORIGINAL:

所以七年之后,你几乎肯定不再需要这个答案......但是,我最近花了一个上午摔跤这个问题,并认为我会给出我的解决方案以防任何类似的不幸在这里结束

首先,任何使用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 Toolkit。

重要提示:

  • 除了unchecked-&gt;选中的转换之外,不应触发ViewGrid.Checked事件,并且一次只能选择一个视图网格。如果这两件事情不成立,您将不得不进行适当的编辑,以确保此代码不会导致无限的事件驱动循环。 (当然,如果你不需要双向绑定,你只需要其中一个事件处理程序和事件乒乓不是一个问题。)
  • 我为一个用户控件写了这个,它在XAML中设置了数据上下文,这就是为什么视图模型的PropertyChanged事件的事件处理程序仅在加载视图后分配。根据您的视图和视图模型彼此绑定的方式和时间,您可能必须分配更早/更晚/不同。
  • 如果视图网格不可见,则此功能无效,GetVisualDescendants似乎忽略隐藏/折叠控件。