繁体   English   中英

如何使用MVVM将命令附加到WPF中的事件 - 更改DataGrid选择以更新TextBlock中显示的RowCount

[英]How to Attach Command to Event in WPF Using MVVM - DataGrid Selection Changed to Update the RowCount Displayed in a TextBlock

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

现在针对这个问题,使用这个AttachedCommandBehaviour ,如何根据DataGridSelectionChangedProperty获取TextBlock进行更新?

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>

我的ViewModel是

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);
        }
    }
}

使用AttachedCommandBehaviour可下载示例的链接就在这里 非常感谢您的帮助......

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

“选择了100件中的5件”

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

捕获

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

我所做的一切都是这样的:

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

这是否已经以某种方式提供帮助,或者是否有理由使用非常复杂的方法来命令事件等?

编辑

你的问题基本上融化为“如何绑定到DataGrid的SelectedItems属性。这是我如何解决它:

使用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中总有一千种方法可以做到,有时很难找到最好的方法......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM