在WPF中的两个用户控件之间发送命令

时间:2014-07-30 08:55:00

标签: c# wpf xaml mvvm user-controls

我试图将命令从一个UserControl发送到另一个Border。第一个包含一个按钮,第二个包含一个派生自Button类的自定义类。

我想点击UserControl中的Redraw method来执行CustomBorderUserControl2中的<Window x:Class="SendCommands.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sendCommands="clr-namespace:SendCommands" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <sendCommands:ViewModel/> </Window.DataContext> <Grid> <Grid.RowDefinitions> <RowDefinition Height="50"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <sendCommands:UserControl1 Grid.Row="0"/> <sendCommands:UserControl2 Grid.Row="1"/> </Grid> </Window>

这是我到目前为止所做的。

MainWindow.xaml:

<UserControl x:Class="SendCommands.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
            <Button Content="Redraw" 
                    Width="200"
                    Height="30"
                    HorizontalAlignment="Center" 
                    VerticalAlignment="Center"/>
    </Grid>
</UserControl>

的UserControl1:

<UserControl x:Class="SendCommands.UserControl2"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:sendCommands="clr-namespace:SendCommands">
    <Grid>
        <sendCommands:CustomBorder Background="Black">

        </sendCommands:CustomBorder>
    </Grid>
</UserControl>

UserControl2:

using System.Windows;
using System.Windows.Controls;

namespace SendCommands
{
    public class CustomBorder : Border
    {
        public void Redraw()
        {
            // Operations to redraw some elements inside the CustomBorder
            MessageBox.Show("We did it!");
        }
    }
}

CustomBorder类:

namespace SendCommands
{
    class ViewModel
    {
    }
}

ViewModel.cs:

MVVM

请有人帮助我一劳永逸地学习。我是{{1}}概念的新手,我已经阅读了很多但没有结果。我真的需要一个实用的解决方案才能使概念正确。

2 个答案:

答案 0 :(得分:3)

你的Redraw方法应该做什么?如果某些属性发生变化,请更改边框例如。商店里的商品已售罄?

在一般视图中应反映ViewModel中的更改。这通过绑定自动发生。 View元素(如按钮)可以使用Commands与ViewModel进行通信。

因此,您的按钮看起来像这样:

<Button Command={Binding ClickCommand} />

在您的ViewModel中,您将拥有

public DelegateCommand ClickCommand {get; private set;}

ClickCommand = new DelegateCommand(ExecuteClick);

ExecuteClick会更新视图模型中的某些属性,例如如果您有在线商店,请将自行车对象的SoldOut属性设置为true。

如果某些属性发生变化,您的视图将依次绑定到Bike的属性并更改其外观。像文本这样的变化会自己发生,转换器可以实现更复杂的变化(例如,在SoldOut中将bckaground更改为红色是真的):

<Resources>
 <SoldOutToBckgrConverter x:Key="soldOutToBckgrConverter" />
</Resources>
<Label Content={Binding Path=SelectedItem.Model} Background={Binding Path=SelectedItem.SoldOut, Converter={StaticResource soldOutToBckgrConverter}} />

SoldOutToBckgrConverter实现IValueConverter并将True转换为红色。

注意:SelectedItem再次绑定到一个列表,其源被绑定到像ViewModel上的ObservableCollection。

所以基本上你不应该调用重绘,它应该全部通过命令,VM和绑定的变化自动重绘。

更新您的评论:这是我试图展示的内容,因为我明白了您重绘的目的。在我的产品示例和销售商品的红色背景中,这将如下所示:

在你的虚拟机中:

public ObservableCollection<MyProduct> Products {get;set;}
private MyProduct selectedProduct;
public MyProduct SelectedProduct
{
get {return selectedProduct;}
set {
if (selectedProduct != value) {
selectedProducat = value;
RaisePropertyChanged(()=>SelectedProduct;
}
}
}

MyProduct具有Model属性(真实世界产品型号,即品牌)和SoldOut。

在您的视图中:

   <ListBox SelectedItem="{Binding SelectedProduct, Mode=TwoWay}" ItemsSource="{Binding Products}" >
<ListBox.ItemTemplate>
<Label Content={Binding Path=SelectedItem.Model} Background={Binding Path=SelectedItem.SoldOut, Converter={StaticResource soldOutToBckgrConverter}} />
</ListBox.ItemTemplate>
</ListBox>

现在,当您单击按钮时,VM会更改SelectedProduct和Binding cahnges背景(或边框..)

答案 1 :(得分:0)

您可以使用Expression Blend提供的“CallMethodAction”行为。将System.Windows.Interactivity.dll添加到您的项目,您可以将方法绑定到事件。在您的情况下,“ReDraw”方法必须绑定到“Click”事件。有关此behavior的更多信息。

  <Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <sendCommands:UserControl1 Grid.Row="0">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="RefreshButtonClick">
                <ei:CallMethodAction MethodName="RedrawCustomBorder"
                                     TargetObject="{Binding ElementName=customBorder}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </sendCommands:UserControl1>
    <sendCommands:UserControl2 Grid.Row="1" x:Name="customBorder"/>
</Grid>