将WPF RelayCommand从DataTemplate绑定到UserControl中的按钮

问题描述 投票:1回答:1

我搜索了很长时间以RelayCommands解决此问题,但找不到类似的解决方案。

问题是我有一个UserControl,并且在这个UserConrol中有一个按钮(在代码末尾处btcNotKnown:]

<UserControl x:Class        = "Vokabelizer.Views.viewLearnSpeak"
         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:Vokabelizer.Views"
         xmlns:conv     = "clr-namespace:Vokabelizer.Global.Converter"
         xmlns:ccont    = "clr-namespace:Vokabelizer.Controls;assembly=Vokabelizer.Controls"
         mc:Ignorable   = "d" 
         d:DesignHeight = "300"
         d:DesignWidth  = "800"
         Height         = "300"
         x:Name         = "root">

<UserControl.Resources>
    ...
</UserControl.Resources>

<Grid Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0">

    <Grid.RowDefinitions>
        ...
    </Grid.RowDefinitions>

    <!-- The question to answer -->
    <Border Grid.Column         = "0"
            Grid.Row            = "0"
            Padding             = "5"
            HorizontalAlignment = "Stretch"
            VerticalAlignment   = "Stretch">

        <TextBlock Text                 = "{Binding Path=LessonNative}"
                   Style                = "{StaticResource UIText}"/>

    </Border>

    <!-- Validation content -->
    <Border Grid.Column         = "0" 
            Grid.Row            = "1"
            Padding             = "5">

        <ToggleButton x:Name        = "QnAToggle"
                      Command       = "{Binding Path=cmdValidateOK}"
                      IsThreeState  = "False">

            <ToggleButton.Style>
                <Style TargetType="ToggleButton" BasedOn="{StaticResource ValidateToggle}">
                    <Style.Triggers>
                        <Trigger Property="IsChecked" Value="False">
                            <Setter Property="Content">
                                <Setter.Value>
                                    <TextBlock Text     = "?"
                                               Style    = "{StaticResource UIText}" />
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter Property="Content">
                                <Setter.Value>
                                    <TextBlock Text     = "{Binding Path=LessonForeign}"
                                               Style    = "{StaticResource UIText}" />
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </ToggleButton.Style>

        </ToggleButton>

    </Border>

    <!-- Result Evaluation buttons -->
    <Border Grid.Column         = "0"
            Grid.Row            = "2">

        <Grid>

            <Grid.ColumnDefinitions>
                ...
            </Grid.ColumnDefinitions>

            <ccont:vokButton x:Name         = "btcNotKnown"
                             Command        = "{Binding Command, ElementName=root}"
                             Grid.Column    = "0"
                             Grid.Row       = "0"
                             Content        = "Not Known"
                             Corner         = "5"
                             Style          = "{StaticResource ValidateNotKnown}"
                             Visibility     = "{Binding ElementName=QnAToggle, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=hidden}" />

        </Grid>

    </Border>

</Grid>

[在UserControl后面的代码中,我定义了DependencyProperty以公开来自UserControl的命令,并因此绑定到UserControls xaml中的Button:

public partial class viewLearnSpeak : UserControl
{
    public viewLearnSpeak()
    {
        InitializeComponent();
    }

    #region DepProp: Command

    public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(viewLearnSpeak), new PropertyMetadata(null));

    public ICommand Command
    {
        get => (ICommand)GetValue(CommandProperty);
        set => SetValue(CommandProperty, value);
    }

    #endregion
}

此用户控件现在在DataTemplate内的窗口内使用,这是麻烦开始的地方:

<DataTemplate DataType="{x:Type vm:vmLearnSpeak}">
    <local:viewLearnSpeak Command="{Binding cmdVMNotKnown, ElementName=root}" />
</DataTemplate>

窗口(视图)绑定到应该承载命令代码的ViewModel(vmSession),因此对于DataTemplate将使用的任何CustomControl,有效的Customcontrol可以将其命令绑定到动作在vmSession ViewModel中(当单击它们所托管的特定按钮时,所有CustomControls都将执行相同的操作)。

后面的代码中的命令定义:

#region Command: Not Known

private ICommand _cmdVMNotKnown;
public ICommand cmdVMNotKnown
{
    get
    {
        if (_cmdVMNotKnown == null)
        {
            _cmdVMNotKnown = new RelayCommand(
                param => this.doVMNotKnown(),
                param => { return true; }
            );
        }
        return _cmdVMNotKnown;
    }
}

protected void doVMNotKnown()
{
}

#endregion

[不幸的是,我只能使绑定以这种方式工作,我没有关于如何将按钮命令绑定到UserControl后面的Viewmodel而是如何以MVVM方式托管UserControls ViewModel的Viewmodel的线索而已,代表或其他处理程序...

这里是全窗口XAML(使用DataTemplate的ContentControl位于结尾):

<Window x:Class         = "Vokabelizer.Views.wndSession"
    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:Vokabelizer.Views"
    xmlns:res       = "clr-namespace:Vokabelizer.Resources"
    xmlns:vm        = "clr-namespace:Vokabelizer.ViewModels"
    mc:Ignorable    = "d"
    Title           = "{x:Static res:Strings.wndLearnTitle}" 
    Height          = "410"
    Width           = "800"
    ResizeMode      = "NoResize"
    x:Name          = "root">

<Window.DataContext>
    <vm:vmSession />
</Window.DataContext>

<Window.Resources>
    <DataTemplate DataType="{x:Type vm:vmLearnSpeak}">
        <local:viewLearnSpeak Command="{Binding cmdVMNotKnown, ElementName=root}" />
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:vmLearnWrite}">
        <local:viewLearnWrite />
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:vmLearnListen}">
        <local:viewLearnListen />
    </DataTemplate>
</Window.Resources>

<Grid Margin="10">

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width = "Auto" />
        <ColumnDefinition Width = "*" />
        <ColumnDefinition Width = "Auto" />
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
        <RowDefinition Height = "50"  />
        <RowDefinition Height = "300" />
    </Grid.RowDefinitions>

    <!-- Title description -->
    <TextBlock x:Name="txtModeDescription"  Text="{Binding LearnTitle}"
               HorizontalAlignment="Left"   VerticalAlignment="Center"
               Grid.Column="0"              Grid.ColumnSpan="1" 
               Grid.Row="0"                 Grid.RowSpan="1"
               Margin="0, 0, 30, 0"        Foreground="DarkGray"
               FontWeight="Bold" FontSize="18" FontFamily="Arial Black" />

    <!-- Progress Slider -->
    <Slider x:Name="sliderProgress"
            HorizontalAlignment="Stretch"   VerticalAlignment="Center"
            Grid.Column="1"                 Grid.ColumnSpan="1" 
            Grid.Row="0"                    Grid.RowSpan="1"
            Minimum="0"                     Maximum="11" />

    <!-- Title status -->
    <TextBlock x:Name="txtBatchAdvancement" Text="{Binding LearnProgressBatch}"
               HorizontalAlignment  = "Right"   VerticalAlignment   = "Center"
               Grid.Column          = "3"       Grid.ColumnSpan     = "1" 
               Grid.Row             = "0"       Grid.RowSpan        = "1"
               Margin               = "10, 0, 0, 0"/>

    <Border Grid.Row            = "1"
            Grid.Column         = "0"
            HorizontalAlignment = "Center"
            VerticalAlignment   = "Center"
            Padding             = "0">

        <Image Source               = "Demo.png"
               Height               = "300"
               Width                = "300"
               HorizontalAlignment  = "Center"
               VerticalAlignment    = "Center" />

    </Border>

    <ContentControl Content     = "{Binding learningViewModel}"
                    Grid.Row    = "1"   Grid.RowSpan="1"
                    Grid.Column = "1"   Grid.ColumnSpan="2"
                    Height      = "300"
                    Margin      = "20, 0, 20, 0"/>

</Grid>

这里是窗口ViewModel中为DataTemplate公开UserControl ViewModel的部分:

private ILearnVM _learningViewModel;
/// <summary>
/// The Learning Provider View Model
/// </summary>
public ILearnVM learningViewModel 
{
    get => this._learningViewModel;
    private set
    {
        this._learningViewModel = value;

        this.OnPropertyChanged(nameof(this.learningViewModel));
    }
}

我搜索了很长时间以使用RelayCommands解决此问题,但找不到类似的解决方案。问题是我有一个UserControl,在此UserConrol中,还有一个按钮(...

c# wpf xaml mvvm relaycommand
1个回答
0
投票

我真的必须感谢@ΩmegaMan和其他要求一些代码正常工作的人。

© www.soinside.com 2019 - 2024. All rights reserved.