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

本文关键字:控件 用户 之间 命令 两个 WPF | 更新日期: 2023-09-27 18:15:28

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

我希望在单击UserControl中的Button时执行UserControl2CustomBorder中的Redraw method

以下是我迄今为止所做的工作。

主窗口.xaml:

<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>

用户控制1:

<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>

用户控制2:

<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>

CustomBorder类:

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!");
        }
    }
}

ViewModel.cs:

namespace SendCommands
{
    class ViewModel
    {
    }
}

请有人帮我一劳永逸地学会这一点。我是MVVM概念的新手,我读了很多书,但没有结果。我真的需要一个实用的解决方案来正确理解这些概念。

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

您的Redraw方法真正应该做什么?如果某些属性已更改,是否更改边框?例如,商店里的一件商品已经卖完了?

一般情况下,视图应反映ViewModel中的更改。绑定会自动发生这种情况。视图元素(如按钮(可以通过命令与ViewModel通信。

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

<Button Command={Binding ClickCommand} />

在你的ViewModel中,你会有一个

public DelegateCommand ClickCommand {get; private set;}

ClickCommand = new DelegateCommand(ExecuteClick);

ExecuteClick会更新视图模型中的一些属性,例如,如果您有一个在线商店,请将bike对象的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转换为Red。

注意:SelectedItem再次绑定到一个列表,该列表的源绑定到ViewModel上的ObservableCollection之类的东西。

所以,基本上你不应该调用redraw,它应该通过命令、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背景(或边界..(

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

  <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>