簡體   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