在 WPF 中,是否可以将 ItemsControl 的 ItemContainerGenerator.StatusChanged 事件作为 MVVM 模式命令获取?
In WPF, is it possible to get the ItemContainerGenerator.StatusChanged event of an ItemsControl as an MVVM pattern command?
在 WPF 中,是否可以将 ItemsControl 的 ItemContainerGenerator.StatusChanged 事件作为 MVVM 模式命令获取?
可以直接获取ItemsControl并注册StatusChanged事件
我想知道是否可以在不直接访问的情况下以 MVVM 模式实现 ItemsControl。
试试这个:
public class ItemContainerGeneratorBehavior
{
public static Dictionary<ItemsControl, EventHandler> HandlersMap = new Dictionary<ItemsControl, EventHandler>();
public static Dictionary<ItemsControl, GeneratorStatus> StatusMap = new Dictionary<ItemsControl, GeneratorStatus>();
public static ICommand GetStatusCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(StatusCommandProperty);
}
public static void SetStatusCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(StatusCommandProperty, value);
}
// Using a DependencyProperty as the backing store for StatusCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StatusCommandProperty =
DependencyProperty.RegisterAttached("StatusCommand", typeof(ICommand), typeof(ItemContainerGeneratorBehavior),
new PropertyMetadata(null, OnStatusCommandChanged));
private static void OnStatusCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var itemsControl = d as ItemsControl;
if (itemsControl == null)
return;
if (e.OldValue != null)
{
if (HandlersMap.ContainsKey(itemsControl))
{
itemsControl.ItemContainerGenerator.StatusChanged -= HandlersMap[itemsControl];
HandlersMap.Remove(itemsControl);
StatusMap.Remove(itemsControl);
}
}
if (e.NewValue != null)
{
HandlersMap[itemsControl] = (_d, _e) => ItemContainerGenerator_StatusChanged(itemsControl, _e);
StatusMap[itemsControl] = itemsControl.ItemContainerGenerator.Status;
itemsControl.ItemContainerGenerator.StatusChanged += HandlersMap[itemsControl];
}
}
private static void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
var itemsControl = sender as ItemsControl;
if (itemsControl == null)
return;
var commandHandler = GetStatusCommand(itemsControl);
var status = itemsControl.ItemContainerGenerator.Status;
var args = new StatusChangedArgs(StatusMap[itemsControl], status);
StatusMap[itemsControl] = status;
if (commandHandler.CanExecute(args))
commandHandler.Execute(args);
}
}
...然后您可以在 ItemsControl 样式中使用...
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.Style>
<Style TargetType="{x:Type ItemsControl}" BasedOn="{StaticResource {x:Type ItemsControl}}">
<Setter Property="behaviors:ItemContainerGeneratorBehavior.StatusCommand" Value="{Binding RelativeSource={RelativeSource Self}, Path=DataContext.StatusChangedCommand}" />
</Style>
</ItemsControl.Style>
</ItemsControl>
...并在您的视图模型中处理...
private ICommand _StatusChangedCommand;
public ICommand StatusChangedCommand => this._StatusChangedCommand ?? (this._StatusChangedCommand = new RelayCommand<StatusChangedArgs>(OnStatusChanged));
private void OnStatusChanged(StatusChangedArgs args)
{
// do something here
}
您还需要这个:
public class StatusChangedArgs
{
public GeneratorStatus OldStatus { get; private set; }
public GeneratorStatus NewStatus { get; private set; }
public StatusChangedArgs(GeneratorStatus oldStatus, GeneratorStatus newStatus)
{
this.OldStatus = oldStatus;
this.NewStatus = newStatus;
}
public override string ToString()
{
return $"{this.OldStatus} -> {this.NewStatus}";
}
}
在 WPF 中,是否可以将 ItemsControl 的 ItemContainerGenerator.StatusChanged 事件作为 MVVM 模式命令获取?
可以直接获取ItemsControl并注册StatusChanged事件 我想知道是否可以在不直接访问的情况下以 MVVM 模式实现 ItemsControl。
试试这个:
public class ItemContainerGeneratorBehavior
{
public static Dictionary<ItemsControl, EventHandler> HandlersMap = new Dictionary<ItemsControl, EventHandler>();
public static Dictionary<ItemsControl, GeneratorStatus> StatusMap = new Dictionary<ItemsControl, GeneratorStatus>();
public static ICommand GetStatusCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(StatusCommandProperty);
}
public static void SetStatusCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(StatusCommandProperty, value);
}
// Using a DependencyProperty as the backing store for StatusCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StatusCommandProperty =
DependencyProperty.RegisterAttached("StatusCommand", typeof(ICommand), typeof(ItemContainerGeneratorBehavior),
new PropertyMetadata(null, OnStatusCommandChanged));
private static void OnStatusCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var itemsControl = d as ItemsControl;
if (itemsControl == null)
return;
if (e.OldValue != null)
{
if (HandlersMap.ContainsKey(itemsControl))
{
itemsControl.ItemContainerGenerator.StatusChanged -= HandlersMap[itemsControl];
HandlersMap.Remove(itemsControl);
StatusMap.Remove(itemsControl);
}
}
if (e.NewValue != null)
{
HandlersMap[itemsControl] = (_d, _e) => ItemContainerGenerator_StatusChanged(itemsControl, _e);
StatusMap[itemsControl] = itemsControl.ItemContainerGenerator.Status;
itemsControl.ItemContainerGenerator.StatusChanged += HandlersMap[itemsControl];
}
}
private static void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
var itemsControl = sender as ItemsControl;
if (itemsControl == null)
return;
var commandHandler = GetStatusCommand(itemsControl);
var status = itemsControl.ItemContainerGenerator.Status;
var args = new StatusChangedArgs(StatusMap[itemsControl], status);
StatusMap[itemsControl] = status;
if (commandHandler.CanExecute(args))
commandHandler.Execute(args);
}
}
...然后您可以在 ItemsControl 样式中使用...
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.Style>
<Style TargetType="{x:Type ItemsControl}" BasedOn="{StaticResource {x:Type ItemsControl}}">
<Setter Property="behaviors:ItemContainerGeneratorBehavior.StatusCommand" Value="{Binding RelativeSource={RelativeSource Self}, Path=DataContext.StatusChangedCommand}" />
</Style>
</ItemsControl.Style>
</ItemsControl>
...并在您的视图模型中处理...
private ICommand _StatusChangedCommand;
public ICommand StatusChangedCommand => this._StatusChangedCommand ?? (this._StatusChangedCommand = new RelayCommand<StatusChangedArgs>(OnStatusChanged));
private void OnStatusChanged(StatusChangedArgs args)
{
// do something here
}
您还需要这个:
public class StatusChangedArgs
{
public GeneratorStatus OldStatus { get; private set; }
public GeneratorStatus NewStatus { get; private set; }
public StatusChangedArgs(GeneratorStatus oldStatus, GeneratorStatus newStatus)
{
this.OldStatus = oldStatus;
this.NewStatus = newStatus;
}
public override string ToString()
{
return $"{this.OldStatus} -> {this.NewStatus}";
}
}