[英]How to bind dependency property of ICommand of ItemsControl member to parent view model?
I have a custom user control that has a checkbox and a button with backing dependency properties.我有一个自定义用户控件,它有一个复选框和一个带有支持依赖属性的按钮。
I also have a window with an ItemsControl and I bind that control's "ItemsSource" to an ObservableCollection containing said user controls.我还有一个带有 ItemsControl 的 window 并将该控件的“ItemsSource”绑定到包含所述用户控件的 ObservableCollection。
My goal is to be able to access the dependency properties in the window's view model, so I can check whether the checkbox of each member of the collection is checked or not and when the user clicks the button - remove the user control containing the button from the collection.我的目标是能够访问窗口视图 model 中的依赖项属性,因此我可以检查集合中每个成员的复选框是否被选中以及当用户单击按钮时 - 删除包含该按钮的用户控件集合。
User control XAML:用户控制XAML:
<CheckBox IsChecked="{Binding cbChecked,
Mode=OneWayToSource,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource FindAncestor,
AncestorType=UserControl}}"/>
<Button Content="X"
Command="{Binding RemoveCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType=UserControl}}">
(note I am not sure if I need the "UpdateSourceTrigger") (注意我不确定是否需要“UpdateSourceTrigger”)
User control codebehind:用户控制代码隐藏:
public ICommand RemoveCommand
{
get { return (ICommand)GetValue(RemoveCommandProperty); }
set { SetValue(RemoveCommandProperty, value); }
}
// Using a DependencyProperty as the backing store for RemoveCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RemoveCommandProperty =
DependencyProperty.Register("RemoveCommand", typeof(ICommand), typeof(CustomUserControl), new PropertyMetadata(OnAnyPropertyChanged));
public bool cbChecked
{
get { return (bool)GetValue(cbCheckedProperty); }
set { SetValue(cbCheckedProperty, value); }
}
// Using a DependencyProperty as the backing store for cbChecked. This enables animation, styling, binding, etc...
public static readonly DependencyProperty cbCheckedProperty =
DependencyProperty.Register("cbChecked", typeof(bool), typeof(CustomUserControl), new PropertyMetadata(OnAnyPropertyChanged));
static void OnAnyPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
=> (obj as CustomUserControl).OnAnyPropertyChanged(args);
void OnAnyPropertyChanged(DependencyPropertyChangedEventArgs args)
=> AnyPropertyChanged?.Invoke(this, args);
Window XAML: Window XAML:
<ScrollViewer VerticalScrollBarVisibility="Visible" Grid.Row="0">
<ItemsControl ItemsSource="{Binding ControlsCollection}" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="FrameworkElement.Margin" Value="5,20,0,0"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</ScrollViewer>
First, you should not hold an element of view in view model.首先,您不应在视图 model 中持有视图元素。 The item of ObservableCollection should be item's view model rather than UserControl.
ObservableCollection 的项目应该是项目的视图 model 而不是 UserControl。
Second, you don't need to use a UserControl in such case.其次,在这种情况下,您不需要使用 UserControl。 A DataTemplate which has the same elements will suffice.
具有相同元素的 DataTemplate 就足够了。
For example, a minimal item's view model would be as follows.例如,最小项目的视图 model 将如下所示。
using CommunityToolkit.Mvvm.ComponentModel;
public partial class ItemViewModel : ObservableObject
{
[ObservableProperty]
public bool _checked;
}
Then, window's view model.然后,窗口视图 model。
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public class MainWindowViewModel : ObservableObject
{
public ObservableCollection<ItemViewModel> ItemsCollection { get; } = new();
public MainWindowViewModel()
{
ItemsCollection.Add(new ItemViewModel());
ItemsCollection.Add(new ItemViewModel());
ItemsCollection.Add(new ItemViewModel());
}
public ICommand RemoveCommand => _removeCommand ??= new RelayCommand<ItemViewModel>(item => Remove(item));
private RelayCommand<ItemViewModel>? _removeCommand;
private void Remove(ItemViewModel? item)
{
if (item is not null)
{
Debug.WriteLine($"Checked:{item.Checked}");
ItemsCollection.Remove(item);
}
}
}
The window's view.窗户的景色。 The elements of DataTemplate of ItemsControl.ItemTemplate are the same as your UserControl but bindings are modified.
ItemsControl.ItemTemplate 的 DataTemplate 的元素与您的 UserControl 相同,但修改了绑定。
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp"
Title="MainWindow"
Width="600" Height="300">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<ScrollViewer VerticalScrollBarVisibility="Visible">
<ItemsControl ItemsSource="{Binding ItemsCollection}"
HorizontalAlignment="Stretch" VerticalAlignment="Top">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="FrameworkElement.Margin" Value="5,20,0,0"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox IsChecked="{Binding Checked, Mode=OneWayToSource}"/>
<Button Content="X"
Command="{Binding DataContext.RemoveCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Self}}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Window>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.