3

为了试图解决这个问题,我在Binding Selected RowCount to TextBlock not Firing OnPropertyChanged after DataGrid Scroll中概述;即在 a滚动时TextBlock使用当前选定的 a 行数更新 a 。DataGrid我试图介绍AttachedCommandBehaviour由 Marlon Grech 设计的 [一个惊人的类结构,它允许您将命令绑定到给定控件的特定事件]。

现在的问题是,使用这个AttachedCommandBehaviour,我怎样才能得到TextBlock基于 aDataGrid的更新SelectionChangedProperty

XMAL 是

<Window x:Class="ResourceStudio.Views.AddCultureWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:viewModels="clr-namespace:ResourceStudio.ViewModels" 
        xmlns:converters="clr-namespace:ResourceStudio.Converters" 
        xmlns:dataAccess="clr-namespace:ResourceStudio.DataAccess" 
        xmlns:attachedCommand="clr-namespace:AttachedCommandBehavior;assembly=AttachedCommandBehavior"
        Title="Add Culture" 
        Height="510" Width="400" 
        WindowStartupLocation="CenterOwner" 
        VerticalContentAlignment="Stretch" 
        MinWidth="380" MinHeight="295">
   <DockPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
      <Grid>
         <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="24"/>
         </Grid.RowDefinitions>

         <Grid>
            <Grid.ColumnDefinitions>
               <ColumnDefinition Width="15*"/>
               <ColumnDefinition Width="377*"/>
               <ColumnDefinition Width="15*"/>
            </Grid.ColumnDefinitions>
            <Grid Grid.Column="1">
               <Grid>
                  <Grid.Resources>
                     <converters:EnumToBooleanConverter x:Key="enumToBooleanConverter"/>
                     <Style x:Key="HyperlinkButton" TargetType="Button">
                        <Setter Property="Template">
                           <Setter.Value>
                              <ControlTemplate TargetType="Button">
                                 <ContentPresenter/>
                              </ControlTemplate>
                           </Setter.Value>
                        </Setter>
                     </Style>
                  </Grid.Resources>
                  <Grid.RowDefinitions>
                     <RowDefinition Height="Auto"/>
                     <RowDefinition Height="1*"/>
                     <RowDefinition Height="Auto"/>
                     <RowDefinition Height="Auto"/>
                     <RowDefinition Height="Auto"/>
                  </Grid.RowDefinitions>
                  <GroupBox Header="Filters" Grid.Row="0" Margin="0,0,0,5">
                     <StackPanel VerticalAlignment="Top">
                        <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="2,2,2,2">
                           <RadioButton Content="All Cultures" Margin="10,5,10,5" 
                                        HorizontalAlignment="Left" 
                                        IsChecked="{Binding SelectedFilterType, 
                                                    Converter={StaticResource enumToBooleanConverter}, 
                                                    ConverterParameter=AllCultures}"/>
                           <RadioButton Content="Neutral Cultures" Margin="10,5,10,5" 
                                        HorizontalAlignment="Left" 
                                        IsChecked="{Binding SelectedFilterType, 
                                                    Converter={StaticResource enumToBooleanConverter}, 
                                                    ConverterParameter=NeutralCultures}"/>
                           <RadioButton Content="Specific Cultures" Margin="10,5,10,5" 
                                        HorizontalAlignment="Left" 
                                        IsChecked="{Binding SelectedFilterType, 
                                                    Converter={StaticResource enumToBooleanConverter}, 
                                                    ConverterParameter=SpecificCultures}"/>
                        </StackPanel>
                        <Grid>
                           <Grid.ColumnDefinitions>
                              <ColumnDefinition Width="Auto"/>
                              <ColumnDefinition Width="*"/>
                           </Grid.ColumnDefinitions>
                           <Label Content="Language:" Grid.Column="0"/>
                           <TextBox HorizontalAlignment="Stretch" Grid.Column="1" 
                                    Margin="2,0,2,0" Height="22"/>
                        </Grid>
                     </StackPanel>
                  </GroupBox>
                  <DataGrid x:Name="cultureDataGrid" Grid.Row="1" AlternatingRowBackground="Gainsboro" AlternationCount="2" 
                            HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                            AutoGenerateColumns="False" RowHeaderWidth="0" IsReadOnly="True"
                            CanUserAddRows="False" CanUserDeleteRows="False" SelectionMode="Extended" 
                            EnableRowVirtualization="True" EnableColumnVirtualization="True" 
                            ItemsSource="{Binding Cultures, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged, IsAsync=True}">
                     <DataGrid.Columns>
                        <DataGridTextColumn Header="Code" Binding="{Binding Code}" IsReadOnly="True"/>
                        <DataGridTextColumn Header="Language" Binding="{Binding Language}" IsReadOnly="True"/>
                        <DataGridTextColumn Header="LocalName" Binding="{Binding LocalName}" IsReadOnly="True"/>
                     </DataGrid.Columns>

                     <DataGrid.CellStyle>
                        <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
                           <Style.Triggers>
                              <Trigger Property="IsSelected" Value="True">
                                 <Setter Property="Background" Value="#FF007ACC"/>
                                 <Setter Property="Foreground" Value="White"/>
                              </Trigger>
                           </Style.Triggers>
                        </Style>
                     </DataGrid.CellStyle>
                     <DataGrid.RowStyle>
                        <Style TargetType="DataGridRow">
                           <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, IsAsync=True}" />
                        </Style>
                     </DataGrid.RowStyle>
                  </DataGrid>
                  <StackPanel Grid.Row="2" HorizontalAlignment="Right">
                     <Button Name="button1" Style="{StaticResource HyperlinkButton}" 
                             Focusable="False">
                        <TextBlock>
                            <Hyperlink Focusable="False">
                                Select All
                            </Hyperlink>
                        </TextBlock>
                     </Button>
                  </StackPanel>
                  <GroupBox Grid.Row="3" Header="Options">
                     <CheckBox Content="Copy default values" Margin="3,3"/>
                  </GroupBox>
                  <StackPanel Grid.Row="4" Orientation="Horizontal" 
                              HorizontalAlignment="Right" Margin="0,2,0,2">
                     <Button Content="Select" Width="70" Height="25" 
                             Margin="0,5,5,5" HorizontalAlignment="Right" 
                             VerticalContentAlignment="Center" IsDefault="True"/>
                     <Button Content="Cancel" Width="70" Height="25" 
                             Margin="5,5,0,5" HorizontalAlignment="Right" 
                             VerticalContentAlignment="Center" IsCancel="True"/>
                  </StackPanel>
               </Grid>
            </Grid>
         </Grid>

         <StatusBar Grid.Row="1" Margin="0,0.4,0.4,-0.4">
            <StatusBarItem DockPanel.Dock="Left" Background="#FF007ACC" Margin="0,2,0,0">
               <TextBlock Text="{Binding TotalSelectedCultures}"  Margin="5,0,0,0" Foreground="White"/>
            </StatusBarItem>
         </StatusBar>
      </Grid>
   </DockPanel>
</Window>

我的视图模型是

public class CultureDataViewModel : ViewModelBase
{
    public FilterType SelectedFilterType { get; private set; }
    public ICollectionView CulturesView { get; private set; }
    public MultiSelectCollectionView<CultureViewModel> Cultures { get; private set; }

    public CultureDataViewModel()
    {
        SelectedFilterType = FilterType.AllCultures;
        LoadCultures();
    }

    void OnCultureViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        string IsSelected = "IsSelected";
        (sender as CultureViewModel).VerifyPropertyName(IsSelected);
        if (e.PropertyName == IsSelected)
            this.OnPropertyChanged("TotalSelectedCultures");
    }

    void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null && e.NewItems.Count != 0)
            foreach (CultureViewModel cultVm in e.NewItems)
                cultVm.PropertyChanged += this.OnCultureViewModelPropertyChanged;

        if (e.OldItems != null && e.OldItems.Count != 0)
            foreach (CultureViewModel cultVm in e.OldItems)
                cultVm.PropertyChanged -= this.OnCultureViewModelPropertyChanged;
    }

    public void LoadCultures()
    {
        // Fill the Culutres collection...
    }

    public string TotalSelectedCultures
    {
        get
        {
            int selectedCultures = this.Cultures.SelectedItems.Count;
            return String.Format("{0:n0} of {1:n0} cultures selected",
                                        selectedCultures,
                                        Cultures.Count);
        }
    }
}

可下载的使用示例的链接AttachedCommandBehaviourHere。非常感谢您的帮助...

4

1 回答 1

8

所以,据我所知,你想要 TextBlock 说:

“已选择 100 个项目中的 5 个”

我已经重建了您的窗口,列表下方的按钮显示您选择了多少项目。

捕获

那是对的吗?如果这真的是您想要做的,那么您根本不需要涉及 ViewModel:

我所做的只是:

<Button Content="{Binding SelectedItems.Count, ElementName=cultureDataGrid}" />

这是否已经在某种程度上有所帮助,或者是否有理由使用带有事件命令等的相当复杂的方法?

编辑

您的问题基本上可以归结为“如何绑定到SelectedItemsDataGrid 的属性。这是我解决它的方法:

使用 DataGrid 的依赖属性定义行为,它将 DataGrid 的 中继SelectedItems到 DependencyProperty:

public class BindableSelectedItems : Behavior<DataGrid>
{
    public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.Register("SelectedItems", typeof (IList), typeof (BindableSelectedItems), new PropertyMetadata(default(IList), OnSelectedItemsChanged));

    private static void OnSelectedItemsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        var grid = ((BindableSelectedItems) sender).AssociatedObject;
        if (grid == null) return;

        // Add logic to select items in grid
    }

    public IList SelectedItems
    {
        get { return (IList) GetValue(SelectedItemsProperty); }
        set { SetValue(SelectedItemsProperty, value); }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
    }

    void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var grid = (DataGrid) sender;
        SelectedItems = grid.SelectedItems;
    }
}

将此行为附加到 DataGrid 并将SelectedItems属性绑定到 ViewModel 上的属性:

<DataGrid x:Name="cultureDataGrid" ItemsSource="{Binding Cultures}">

    <i:Interaction.Behaviors>
        <behaviors:BindableSelectedItems x:Name="CulturesSelection" 
                                         SelectedItems="{Binding SelectedCultures, Mode=OneWayToSource}"/>
    </i:Interaction.Behaviors>

使用 ViewModel 上的属性,如下所示:

public IList SelectedCultures
{
    get { return _selectedCultures; }
    set
    {
        _selectedCultures = value;
        OnPropertyChanged("SelectedCultures");
    }
}

如果您只想获取所选项目的计数,您可以直接绑定到行为,并且不需要 ViewModel 上的字段:

<TextBlock Text="{Binding Path=SelectedItems.Count, ElementName=CulturesSelection}" Margin="5,0,0,0" Foreground="White"/>

在您的 ViewModel 中,您可以使用该SelectedItems属性来处理选择:

var selectedCultures= SelectedCultures.OfType<CultureViewModel>();

我已经上传了解决方案,请参阅评论中的链接。

我希望这会有所帮助,并祝你好运!在 WPF 中总是有一千种方法可以做事,有时真的很难找到最好的……

于 2013-07-10T11:32:59.453 回答