WPF项目+ Prism 7 +(纯MVVM模式)
简单,我有TextBox
,当按下某些按钮时需要清除(不违反MVVM模式)
<Button Command="{Binding ClearCommand}"/>
<TextBox Text="{Binding File}">
<i:Interaction.Behaviors>
<local:ClearTextBehavior ClearTextCommand="{Binding ClearCommand, Mode=OneWayToSource}" />
</i:Interaction.Behaviors>
</TextBox>
ViewModel
public class ViewModel {
public ICommand ClearCommand { get; set; }
}
行为
public class ClearTextBehavior : Behavior<TextBox>
{
public ICommand ClearTextCommand
{
get { return (ICommand)GetValue(ClearTextCommandProperty); }
set
{
SetValue(ClearTextCommandProperty, value);
RaisePropertyChanged();
}
}
public static readonly DependencyProperty ClearTextCommandProperty =
DependencyProperty.Register(nameof(ClearTextCommand), typeof(ICommand), typeof(ClearTextBehavior));
public ClearTextBehavior()
{
ClearTextCommand = new DelegateCommand(ClearTextCommandExecuted);
}
private void ClearTextCommandExecuted()
{
this.AssociatedObject.Clear();
}
}
问题是,尽管我确保已在行为类中将其初始化,但ViewModel中的命令始终为null(未绑定到Behavior中的命令)。
注意:请不要建议将File属性设置为空字符串,因为这只是一个示例,在我的实际情况下,我需要选择所有Text,因此我确实需要访问{ {1}}的行为
答案 0 :(得分:1)
如果我正确理解了您的问题,您想知道为什么ICommand
中的ViewModel
未设置为DelegateCommand
中定义的Behaviour
。
问题是ICommand
和DelegateCommand
没有直接连接。我认为您可能会误解了Binding
的工作原理以及使用它们会发生什么。
首先,ICommand
来自Class
,因此是引用类型。
第二,对ICommand
的引用保存在DependencyProperty
ClearTextCommandProperty
中。
第三,通过在Binding
中使用XAML
,这种情况以C#代码的形式发生:
Binding binding = new Binding();
binding.Path = new PropertyPath("ClearTextCommand");
binding.Source = ClearCommand;
BindingOperations.SetBinding(TextBox.ClearTextCommandProperty, binding);
现在重要的是:我不知道到底是哪个赋值最先出现,但是这两行都将覆盖Value
中的ClearTextCommandProperty
引用!
//either here
SetBinding(TextBox.ClearTextCommandProperty, binding);
//or here
ClearTextCommand = new DelegateCommand(ClearTextCommandExecuted);
//Which could be written as
SetValue(ClearTextCommandProperty, new DelegateCommand(ClearTextCommandExecuted));
在任何时候都没有这样的作业:
ViewModel.ClearCommand = SomeICommand;
因此它是Null
,就像@Andy所说的
已编辑以匹配所有文本
另外,我建议您放弃这种复杂的东西,并像这样利用Interactivity
软件包的全部潜能:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<Button>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<utils:SelectAllText TargetName="TextToSelect"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<TextBox x:Name="TextToSelect" Text="{Binding File}"/>
还有SelectAllText
public class SelectAllText : TargetedTriggerAction<TextBox>
{
protected override void Invoke(object parameter)
{
if (Target == null) return;
Target.SelectAll();
Target.Focus();
}
}
答案 1 :(得分:0)
如果您在此处查看此示例: https://social.technet.microsoft.com/wiki/contents/articles/31915.wpf-mvvm-step-by-step-1.aspx 您会注意到,我那里有一个ICommand,它已设置为运行方法。
如果它只是一个具有Get和Set的ICommand,那么它将为NULL。有一个属性,但在设置为某项之前为空。
这是实现ICommand的笨拙方式,但不依赖任何外部库或任何东西。
如果您看一下该系列的第二篇文章,它使用了mvvmlight和relaycommand,因此创建命令相当麻烦。
https://social.technet.microsoft.com/wiki/contents/articles/32164.wpf-mvvm-step-by-step-2.aspx
public RelayCommand AddListCommand { get; set; }
public MainWindowViewModel()
{
AddListCommand = new RelayCommand(AddList);
}
private void AddList()
{
stringList.Add(myString));
}
如果您查看该代码,AddListCommand最初为空。 在构造函数中将其设置为新的RelayCommand,这意味着它不为null。
这很简单,但是命令的代码与属性位于不同的位置,因此通常使用更优雅的方法。如此处所示:https://msdn.microsoft.com/en-gb/magazine/dn237302.aspx
说了这么多。 选择所有文本是视图中要做的事情,而不是视图模型。 您实际上不应该将一部分UI从视图传递到ViewModel。
您应该绑定一个在视图模型中设置并按照行为执行的布尔,而不是命令。