我正在使用MVVM进行示例并且遇到命令问题。我有一个Article类(带有ID,Name,Price等),一个表示视图模型的ArticleViewModel,以及一个允许输入文章数据的用户控件(ArticleControl),它绑定了ArticleViewModel的属性。此用户控件具有保存命令的biding。
<UserControl.CommandBindings>
<CommandBinding x:Name="saveCmd"
Command="local:Commands.Save"
CanExecute="CommandBinding_CanExecute"
Executed="CommandBinding_Executed"/>
</UserControl.CommandBindings>
这是命令的定义方式:
public class Commands
{
private static RoutedUICommand _save;
public static RoutedUICommand Save
{
get { return _save; }
}
static Commands()
{
InputGestureCollection saveInputs = new InputGestureCollection();
saveInputs.Add(new KeyGesture(Key.S, ModifierKeys.Control, "Ctrl+S"));
_save = new RoutedUICommand(
"Save",
"Save",
typeof(Commands),
saveInputs);
}
}
命令绑定处理程序:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
double baseprice = 0;
double.TryParse(ArticleBasePrice.Text, out baseprice);
e.CanExecute =
!string.IsNullOrEmpty(ArticleID.Text) &&
!string.IsNullOrEmpty(ArticleName.Text) &&
!string.IsNullOrEmpty(ArticleDescription.Text) &&
baseprice > 0;
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
ArticleViewModel avm = (ArticleViewModel)DataContext;
if (avm != null && avm.Save())
{
ArticleID.Text = String.Empty;
ArticleName.Text = String.Empty;
ArticleDescription.Text = String.Empty;
ArticleBasePrice.Text = String.Empty;
}
}
现在,我将此用户控件放在窗口上。当我按下Ctrl + S时,执行命令。但是,我还在该窗口旁边的用户控件旁边放了一个Save按钮。当我单击它时,我想执行相同的命令(我不想在托管用户控件的窗口中执行另一个命令绑定)。
<StackPanel>
<local:ArticleControl x:Name="articleControl" />
<Button Name="btnSave"
Content="Save" Width="100"
HorizontalAlignment="Left"
Command="{???}"/> <!-- what should I put here? -->
</StackPanel>
但我不知道如何引用用户控件中定义的saveCmd。我尝试了不同的东西,有些是完全错误的(他们在运行应用程序时抛出异常),有些没有任何影响。
Command="{StaticResource saveCmd}"
Command="{StaticResource local:ArticleControl.saveCmd}"
Command="{x:Static local:Commands.Save}"
感谢任何帮助。谢谢。
答案 0 :(得分:3)
“保存”按钮不会导致其他控件的命令绑定执行的原因是“保存”按钮位于用户控件之外,因此命令系统不会在该控件中查找命令绑定。 Command执行策略有点像冒泡事件,它将从焦点项(Button)开始,然后上升到可视树,直到找到CommandBindings。
您可以在父控件中实现命令绑定,也可以将Save按钮的CommandTarget
属性设置为用户控件。
另一种方法是在按钮或按钮的容器上设置FocusManager.IsFocusScope=True
。如果你这样做,我建议你阅读IsFocusScope
的内容,但简而言之,当你按下按钮时,它会将输入焦点留在任何具有焦点的控件上,而不是让按钮成为新的输入焦点。这通常用于工具栏或类似菜单的结构。
答案 1 :(得分:1)
我认为您只需要将CommandBinding
移动到资源字典,以便它可以在UserControl之外使用!
答案 2 :(得分:1)
根据帕特里克的建议,这就是我所做的:
将命令绑定放在用户控件中,并在代码隐藏中实现处理程序,如原始消息所示。
按钮上使用的Command
,CommandTarget
和FocusManager
属性指向用户控件的绑定(ArticleUserControl
是x:Name
用户控件)。
这就是窗口的XAML外观:
<Window x:Class="MVVMModel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMModel"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<local:ArticleControl x:Name="articleControl" />
<Button Name="btnSave" Content="Save" Width="100" HorizontalAlignment="Left"
Command="local:Commands.Save"
CommandTarget="{Binding ElementName=ArticleUserControl}"
FocusManager.IsFocusScope="True" />
</StackPanel>
</Window>
答案 3 :(得分:0)
这是我的工作,虽然我对解决方案并不是特别满意。如果有人知道更好的方法,请告诉我。
我在一个单独的静态类中移动了命令处理程序的逻辑:
static class CommandsCore
{
public static bool Save_CanExecute(ArticleControl ac)
{
double baseprice = 0;
double.TryParse(ac.ArticleBasePrice.Text, out baseprice);
return
!string.IsNullOrEmpty(ac.ArticleID.Text) &&
!string.IsNullOrEmpty(ac.ArticleName.Text) &&
!string.IsNullOrEmpty(ac.ArticleDescription.Text) &&
baseprice > 0;
}
public static void Save_Executed(ArticleControl ac)
{
ArticleViewModel avm = (ArticleViewModel)ac.DataContext;
if (avm != null && avm.Save())
{
ac.ArticleID.Text = String.Empty;
ac.ArticleName.Text = String.Empty;
ac.ArticleDescription.Text = String.Empty;
ac.ArticleBasePrice.Text = String.Empty;
}
}
}
我将命令绑定保存在用户控件中,因为它是
<UserControl.CommandBindings>
<CommandBinding x:Name="saveCmd"
Command="local:Commands.Save"
CanExecute="CommandBinding_CanExecute"
Executed="CommandBinding_Executed"/>
</UserControl.CommandBindings>
但在处理程序中,我调用了上面定义的两种方法。
public void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = CommandsCore.Save_CanExecute(this);
}
public void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
CommandsCore.Save_Executed(this);
}
然后我从使用控件的窗口做了同样的事情。
<Window x:Class="MVVMModel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMModel"
Title="MainWindow" Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding x:Name="saveCmd"
Command="local:Commands.Save"
CanExecute="CommandBinding_CanExecute"
Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
<StackPanel>
<local:ArticleControl x:Name="articleControl" />
<Button Name="btnSave" Content="Save" Width="100" HorizontalAlignment="Left"
Command="local:Commands.Save"/>
</StackPanel>
</Window>
和处理程序
public void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = CommandsCore.Save_CanExecute(articleControl);
}
public void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
CommandsCore.Save_Executed(articleControl);
}
这样,只有在相应填写字段并且单击按钮时正确执行命令时,才会启用“保存”按钮。