我已经创建了一个名为AnswerUserControl
的UserControl。 XAML文件如下所示(唯一的按钮):
<UserControl
...>
<Button
DataContext="{Binding Path=ViewModel,
RelativeSource={
RelativeSource Mode=FindAncestor,
AncestorType={x:Type UserControl}
}}"
Command="{Binding Path=ClickCommand}"
Content="{Binding Path=Reply}" />
</UserControl>
还有cs
个具有AnswerViewModel
依赖项的文件:
public partial class AnswerUserControl : UserControl
{
public AnswerUserControl()
{
InitializeComponent();
}
public AnswerViewModel ViewModel
{
get
{
return (AnswerViewModel)GetValue(ViewModelProperty);
}
set
{
SetValue(ViewModelProperty, value);
}
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(AnswerViewModel), typeof(AnswerUserControl));
}
AnswerViewModel类:
public class AnswerViewModel : ViewModelBase
{
private string reply;
public string Reply
{
get
{
return reply;
}
set
{
reply = value;
RaisePropertyChanged(nameof(Reply));
}
}
private ICommand clickCommand;
public ICommand ClickCommand
{
get
{
return clickCommand;
}
set
{
clickCommand = value;
RaisePropertyChanged(nameof(ClickCommand));
}
}
public AnswerViewModel(Action<int> click, string reply, int index)
{
void Click()
{
Console.WriteLine($"AnswerViewModel click at {index}");
click(index);
}
Reply = reply;
ClickCommand = new RelayCommand(Click);
}
}
在Window中,我像这样添加UserContol:
<StackPanel>
<local:AnswerUserControl
ViewModel="{Binding Path=VMA}" />
</StackPanel>
VMA
是Window的ViewModel中的AnswerViewModel
:
private AnswerViewModel vma;
public AnswerViewModel VMA
{
get
{
return vma;
}
set
{
vma = value;
RaisePropertyChanged(nameof(VMA));
}
}
static int number = 1;
public HomeViewModel()
{
VMA = new AnswerViewModel(x => { Console.WriteLine($"Click Number: {number++}"); }, "Reply", 0);
}
我面临的问题是ClickCommand仅执行了几次。当我缓慢单击按钮时,它会执行4至6次,而当我快速单击按钮时,它将执行20次以上,然后它将停止工作。我在哪里弄错了?
答案 0 :(得分:1)
我写了一个如何实现的粗略版本。对于主窗口,我们可以使用以下代码。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowDataContext();
}
}
如上所示,我们向主窗口分配了一个视图模型,在这个视图模型中,我们可以为用户控件定义一个数据上下文。给我们下面的代码;
public class MainWindowDataContext : INotifyPropertyChanged
{
public MainWindowDataContext()
{
newDatacontext = new DataContextTest();
}
private DataContextTest _newDatacontext;
public DataContextTest newDatacontext
{
get => _newDatacontext;
set
{
if(_newDatacontext == value)
return;
_newDatacontext = value;
OnPropertyChanged(nameof(newDatacontext));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
不要介意接口或getter / setter,这纯粹是为了演示如何通知绑定属性已更改。
在MainWindowDataContext内,我们创建一个DataContextTest类。这个viewmodel / datacontext类包含我们的命令,并且可以为usercontrol保留其他绑定。
public class DataContextTest
{
public ICommand ButtonCommand => new RelayCommand(executeThis);
private void executeThis()
{
Console.WriteLine($"VM clicked ");
}
}
对于xaml代码和绑定所在的前端,我编写了以下内容: 一个具有按钮的用户控件,在主窗口中插入了该用户控件。
<Window x:Class="Tryout.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Tryout"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:UserControl1 DataContext="{Binding newDatacontext,UpdateSourceTrigger=PropertyChanged}"></local:UserControl1>
</Grid>
主窗口使用MainWindowDataContext,这是在构造函数中分配的(请参见代码块1)。 MainWindowDataContext为需要数据上下文的用户控件提供了一个getter设置方法。数据上下文更改时,userControl会收到通知。
在查看用户控件xaml时,我们看到以下内容
<UserControl x:Class="Tryout.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Tryout"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Button Command="{Binding ButtonCommand}" Width="200" Height="100" Content="test"/>
</Grid>
使用所有这些代码,它可以解析为视图模型的以下层次结构。
MainWindow-> MainWindowDataContext-> DataContextTest。
因为MainWindow使用UserControl,所以我们需要为MainWindow定义一个视图模型。设置好之后,您可以通过前端绑定将datacontext / viewmodel分配给usercontrol。
不需要Dependecy属性,在大多数情况下,数据上下文就足够了(: