【问题标题】:access command defined in nested user controls wpf在嵌套用户控件 wpf 中定义的访问命令
【发布时间】:2017-02-10 22:13:36
【问题描述】:

我有一个从Window 类派生的MainWindow。该窗口有一个ContentControl,用于在其中托管用户UserControl 对象。我正在尝试创建一个按钮来访问在嵌套的UserControl 中定义的Command。唯一的技巧是我的用户控件实际上也嵌套了更多的用户控件,而且我实际上是在使用grand-child 命令而不仅仅是一个孩子。像这样:

主窗口:

<metro:MetroWindow  x:Class="GrimshawRibbon.Revit.Wpf.MainWindow"
                    x:Name="win"
                    xmlns:metro="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
                    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:pmModel="clr-namespace:GrimshawRibbon.Revit.Management.ParametersManagerWPF.ViewModel"
                    xmlns:pmLocal="clr-namespace:GrimshawRibbon.Revit.Management.ParametersManagerWPF"
                    xmlns:local="clr-namespace:GrimshawRibbon.Revit.Wpf"
                    mc:Ignorable="d" Height="400" Width="600" ResizeMode="CanResizeWithGrip" 
                    Title="{Binding WindowTitle, Mode=OneWay, FallbackValue='GrimshawDT'}" BorderBrush="{DynamicResource AccentColorBrush}" BorderThickness="1"
                    WindowStartupLocation="CenterScreen" WindowTransitionsEnabled="False">
    <metro:MetroWindow.Resources>
        <ResourceDictionary>
            <DataTemplate DataType="{x:Type pmModel:pmViewModel}">
                <pmLocal:pmMain />
            </DataTemplate>
        </ResourceDictionary>
    </metro:MetroWindow.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height = "100" />
            <RowDefinition/>
        </Grid.RowDefinitions>

        <ContentControl x:Name="MainContentControl" Content="{Binding CurrentPageViewModel}" Margin="10" Grid.Row="1"/>
        <Button x:Name="btnOK" Content="OK" Margin="0,0,211,10" HorizontalAlignment="Right" Width="75" Height="36" VerticalAlignment="Bottom" Command="{Binding pmModel:pmViewModel.ApplyCommand, Mode=OneWay}" Grid.Row="1" metro:ButtonHelper.CornerRadius="0" metro:ControlsHelper.ContentCharacterCasing="Normal" BorderThickness="1" metro:ButtonHelper.PreserveTextCase="True"/>
    </Grid>
</metro:MetroWindow>

嵌套在 MainWindow 中的控件:

<UserControl x:Class="GrimshawRibbon.Revit.Management.ParametersManagerWPF.pmMain"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
             xmlns:ignore="http://www.ignore.com"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:GrimshawRibbon.Revit.Management.ParametersManagerWPF" 
             xmlns:viewModel="clr-namespace:GrimshawRibbon.Revit.Management.ParametersManagerWPF.ViewModel"
             xmlns:Custom="http://metro.mahapps.com/winfx/xaml/controls"
             mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="600">
    <UserControl.Resources>
        <ResourceDictionary>
            <DataTemplate DataType="{x:Type viewModel:pmSetParamToValueViewModel}">
                <local:pmSetParamToValueView />
            </DataTemplate>
            <DataTemplate DataType="{x:Type viewModel:pmCopyParamToParamViewModel}">
                <local:pmCopyParamToParamView />
            </DataTemplate>
            <DataTemplate DataType="{x:Type viewModel:pmCopyParamToParamSliceViewModel}">
                <local:pmCopyParamToParamSliceView />
            </DataTemplate>
            <DataTemplate DataType="{x:Type viewModel:pmCombineTwoSlicesViewModel}">
                <local:pmCombineTwoSlicesView />
            </DataTemplate>
        </ResourceDictionary>
    </UserControl.Resources>
    <Grid>
        <ComboBox x:Name="cbType" Margin="0,26,0,0" Height="22" VerticalAlignment="Top" ItemsSource="{Binding PageNames}" SelectedIndex="{Binding SelectedVMIndex}" Custom:TextBoxHelper.Watermark="Parameter Manager Functionality"/>
        <ContentControl x:Name="contentControl" Content="{Binding CurrentPageViewModel}" Margin="0,57,0,0"/>
        <Label x:Name="label" Content="Select Functionality:" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="Bold"/>
    </Grid>
</UserControl>

这反过来有更多这样的嵌套控件:

<UserControl x:Class="GrimshawRibbon.Revit.Management.ParametersManagerWPF.pmSetParamToValueView"
             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:GrimshawRibbon.Revit.Management.ParametersManagerWPF"
             xmlns:Custom="http://metro.mahapps.com/winfx/xaml/controls" 
             mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="200">
    <Grid>
        <ComboBox x:Name="cbCategories" HorizontalAlignment="Left" VerticalAlignment="Top" Width="180" ItemsSource="{Binding Categories}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedCategory}" Custom:TextBoxHelper.Watermark="Category" Margin="0,26,0,0"/>
        <ComboBox x:Name="cbSourceParam" HorizontalAlignment="Left" Margin="0,57,0,0" Width="180" Height="22" VerticalAlignment="Top" ItemsSource="{Binding Parameters}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedParameter}" Custom:TextBoxHelper.Watermark="Source Parameter"/>
        <TextBox x:Name="tbParamValue" Margin="185,57,0,0" Height="23" VerticalAlignment="Top" Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Custom:TextBoxHelper.Watermark="Parameter Value"/>
        <Label x:Name="label" Content="Define Parameters:" HorizontalAlignment="Left" VerticalAlignment="Top" FontWeight="Bold"/>
    </Grid>
</UserControl>

现在,当在主窗口中点击 OK 按钮时,我希望第二个嵌套控件执行 ApplyCommand。这是我的第二个用户控件的视图模型:

namespace GrimshawRibbon.Revit.Management.ParametersManagerWPF.ViewModel
{
    public class pmSetParamToValueViewModel : ViewModelBase
    {
        public pmModel model;
        public ObservableCollection<CategoryWrapper> Categories { get; private set; }
        public RelayCommand ApplyCommand { get; private set; }

        public pmSetParamToValueViewModel(Document doc)
        {
            this.model = new pmModel(doc);
            this.Categories = model.CollectCategories();
            SelectedCategory = Categories[0];
            this.ApplyCommand = new RelayCommand(this.Apply);
        }

        // logic for apply button
        private void Apply()
        {
            model.Apply(SelectedCategory.ID, SelectedParameter, null, null, Value, null, null, null, "Apply");
        }

        // logic for storing parameter value
        private string _value;
        public string Value
        {
            get { return _value; }
            set
            {
                if (_value == value) return;

                _value = value;
                RaisePropertyChanged(() => Value);
            }
        }

        // storage for source parameters
        private ObservableCollection<ParameterWrapper> _parameters;
        public ObservableCollection<ParameterWrapper> Parameters
        {
            get { return _parameters; }
            set
            {
                if (_parameters == value) return;

                _parameters = value;
                RaisePropertyChanged(() => Parameters);
                if (Parameters.Count > 0)
                {
                    SelectedParameter = Parameters[0];
                }
            }
        }

        // logic for selected category
        private CategoryWrapper _selectedCategory;
        public CategoryWrapper SelectedCategory
        {
            get { return _selectedCategory; }
            set
            {
                if (_selectedCategory == value) return;

                _selectedCategory = value;
                RaisePropertyChanged(() => SelectedCategory);
                Parameters = model.CollectParameters(SelectedCategory.ID, new string[] { "String", "Double", "Integer" });
            }
        }

        // logic for selected source parameter
        private ParameterWrapper _selectedParameter;
        public ParameterWrapper SelectedParameter
        {
            get { return _selectedParameter; }
            set
            {
                if (_selectedParameter == value) return;

                _selectedParameter = value;
                RaisePropertyChanged(() => SelectedParameter);
            }
        }
    }
}

谁能告诉我如何在主窗口中设置“确定”按钮,以便能够访问在嵌套用户控件中定义的命令。或者,有没有办法设置一个确定按钮来检索给定嵌套用户控件的当前状态,以便我可以检索它们的属性并将它们用作我的ApplyCommand 的参数?

干杯!

【问题讨论】:

    标签: c# wpf command


    【解决方案1】:

    看起来好像您已经在主视图模型中引用了子视图模型,所以我相信这应该可行:

    <Button x:Name="btnOK" Content="OK" Margin="0,0,211,10" HorizontalAlignment="Right" Width="75" Height="36" VerticalAlignment="Bottom" Command="{Binding CurrentPageViewModel.CurrentPageViewModel.ApplyCommand}" Grid.Row="1" metro:ButtonHelper.CornerRadius="0" metro:ControlsHelper.ContentCharacterCasing="Normal" BorderThickness="1" metro:ButtonHelper.PreserveTextCase="True"/>
    

    【讨论】:

    • 是的,这很好用。谢谢你。我会给你赏金。然而,我确实意识到我所要求的并不是我真正想做的。我并不总是将用户控件嵌套在另一个用户控件中。有时(大多数时候)我只有一个用户控件。为了处理这两种情况,我想像Binding CurrentPageViewModel.ApplyCommand 那样绑定那个按钮,然后将ApplyCommandApply 方法放在主用户控件中,如果可能的话从那里开始。有没有办法从ViewModel 中的代码访问我的嵌套控件?
    • 问题是 CurrentPageViewModel 是一个基类 ViewModelBase 并且不允许我访问其中的方法。由于当前页面可以是任何视图模型,因此我需要将其转换为选定的特定页面,然后才能访问其方法。 :-( 我可以实现自己的基本视图模型并向其添加 Apply 方法,以便它始终可用。这是一种方法吗?
    • 我不确定我是否理解,所以如果这在您的场景中不起作用,我们深表歉意,但也许您可以按照您的建议将您的按钮绑定到 CurrentPageViewModel.ApplyCommand,但有一些类似的东西这个: if (this.CurrentPageViewModel != null) { this.CurrentPageViewModel.ApplyCommand.Execute() } else { this.Apply(); }
    • 我刚刚扩展了ViewModelBase 类并添加了ApplyCommand,以便我可以从基础级别访问它。这个对我有用。感谢所有 cmets。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    相关资源
    最近更新 更多