[英]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
,如何根据DataGrid
的SelectionChangedProperty
获取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.