在另一个viewmodel中执行命令?

时间:2014-04-25 08:39:32

标签: c# wpf xaml mvvm icommand

我有一个从ComboBox派生的自定义“DateRangeSelector”控件。这是一个带有以下过滤器的下拉控件:
1.今天 2.接下来的三天
3.接下来的三周时间 4.自定义范围(允许用户设置自定义日期范围)

现在这个“DateRangeSelector”控件被添加到另一个XAML(ActivityListMenuControlView.xaml)中:

<DateRangeSelector:DateRangeSelectorControl x:Name="DateRangeSelector"
    Grid.Column="1"
    Margin="10 0 0 0"
    HorizontalAlignment="Left"
    VerticalAlignment="Center"
    AutomationProperties.AutomationId="AID_TaskListDateRangeSelector"
    DateRangeUpdatedCmd="{Binding Path=DateRangeSelectionUpdatedCommand}"
    TodayDateUpdatedCmd="{Binding Path=TodayDateUpdatedCommand}"
    FontSize="{StaticResource TaskListMenuFontSize}"
    RangeOptions="{Binding Path=DateRangeSelectionOptions,
    Mode=OneTime}"
    SelectedDateRange="{Binding Path=SelectedRange,
    Mode=TwoWay}"
    Visibility="{Binding Path=ShowFilterOptions,
    Converter={StaticResource boolToVisibility}}" />

从上面的代码可以看出,我在“DateRangeSelector”中创建了一个命令“TodayDateUpdatedCmd”,用于在系统日期发生变化时绑定到此控件中的“今天”过滤器并绑定到“ActivityListMenuControlViewModel”中的命令“TodayDateUpdatedCommand”。
更新日期的代码存在于“DateRangeSelector”本身的方法“SetDateValues”中。 我只是对如何从“ActivityListMenuControlViewModel”执行此方法感到困惑? 请帮忙。

更新: DateRangeSelector只是一个没有view / viewmodel的类。这是代码:

public class DateRangeSelectorControl : ComboBox, INotifyPropertyChanged
{
                  public static readonly DependencyProperty TodayDateUpdateCmdProperty = DependencyProperty.Register("TodayDateUpdatedCmd", typeof(ICommand), typeof(DateRangeSelectorControl),
    new PropertyMetadata(null));

    public ICommand TodayDateUpdatedCmd
    {
        get { return (ICommand)this.GetValue(TodayDateUpdateCmdProperty); }
        set
        {
            this.SetValue(TodayDateUpdateCmdProperty, value);
        }
    }

         /// <summary>
    /// 
    /// </summary>
    private void SetDateValues()
    {
        DateTime todaysDate = DateTime.Now;

        TodayText = Utility.GetStringFromResource("TodayLabel") + " (" + todaysDate.ToShortDateString() + ")";

        NextThreeDaysText = Utility.GetStringFromResource("NextThreeDaysLabel") + " (" + todaysDate.ToShortDateString() + " - " + todaysDate.AddDays(3).ToShortDateString() + ")";

        NextWeekText = Utility.GetStringFromResource("NextWeekLabel") + " (" + todaysDate.ToShortDateString() + " - " + todaysDate.AddDays(7).ToShortDateString() + ")";

        SetCustomDateRangeText();
    }
}

从上面的代码可以看出,我首先注册了一个依赖属性“TodayDateUpdateCmdProperty”和命令属性“TodayDateUpdatedCmd”,它在“ActivityListMenuControlView.xaml”中使用,如XAML片段中所示。此外,我需要在DateRangeSelector类中执行方法“SetDateValues”来更新今天的日期。 现在请帮我解决一下这个问题?

更新: 根据@GazTheDestroyer的建议,我对代码进行了更改,现在没有使用任何命令。但现在使用以下详细信息获取运行时XamlParseException:

“'匹配指定绑定约束的类型'VMS.Nexus.Client.Common.Controls.DateRangeSelector.DateRangeSelectorControl'上的构造函数的调用引发了异常。行号“45”和行位置“14”。“}

的InnerException: {“默认值类型与属性'TodayDate'的类型不匹配。”}

在ActivityListMenuControlView.xaml中抛出此异常,我创建了DateRangeSelector。 请帮忙

2 个答案:

答案 0 :(得分:0)

特别是在编写WPF和MVVM时,开发人员通常会使用我们可以在视图模型中声明的delegate ICommand形式。您可以在MSDN上WPF Apps With The Model-View-ViewModel Design Pattern页面的“中继命令逻辑”部分中找到常用RelayCommand的实施详细信息。您可以在Stack Overflow上的How can I use the RelayCommand in wpf?问题中找到它的基本使用示例。

因此,您可以在视图模型中定义ICommand个实例,并将数据绑定到控件。对于DateRangeSelector,您只需声明类型为DependencyProperty的{​​{1}},并将数据绑定到您的视图模型中的数据......可能是这样的:

ICommand

在您的视图模型中:

<DateRangeSelector:DateRangeSelectorControl TodayDateUpdatedCmd="{Binding Command}">
    ...
</DateRangeSelector:DateRangeSelectorControl>

更新&gt;&gt;&gt;

很简单地说,没有必要在WPF中的这个(或几乎任何)实例中扩展public ICommand Command { get { return new ActionCommand(action => DoSomething(), canExecute => CanDoSomething(); } } 类。有关无需执行此操作的原因的详细信息,请参阅MSDN上的Control Authoring Overview页面。

所以基本的想法是,你将功能从ComboBox移到另一个类......一个视图模型类。然后,您可以将数据绑定到ComboBox并提供功能。在WPF中,我们操纵数据,而不是 UIElement 。因此,而不是定义所有的过滤器&#39;在控件中,在代码中定义它们。

首先,您需要一个包含可用日期的集合属性:

ComboBox

接下来,您应该有一个public ObservableCollection<DateTime> AvailableDates { get { return availableDates; } set { availableDates = value; NotifyPropertyChange("AvailableDates"); } } ,其值代表每种过滤器类型。您可以在视图模型中添加此类型的属性,该属性可以控制每次更改时enum中显示的项目:

ComboBox

...

public FilterType FilterType
{
    get { return filterType; }
    set
    {
        filterType = value; 
        NotifyPropertyChange("FilterType");
        FillAvailableDatesDependantOnFilterType();
    }
}

希望你现在有了更好的主意。

答案 1 :(得分:0)

命令应该由控件 触发,而不是用作您似乎正在尝试的控件的通知机制。

如果您的控件需要对某些更改的变量做出反应,那么它应该公开DependencyProperty并对其进行更改。例如,在DateRangeSelectorControl

的代码中
public static readonly new DependencyProperty TodaysDateProperty=
            DependencyProperty.Register("TodaysDate", typeof(DateTime), typeof(DateRangeSelectorControl), new PropertyMetadata(null, TodaysDateChanged));

public new DateTime TodaysDate
{
    get { return (DateTime)GetValue(TodaysDateProperty); }
    set { SetValue(TodaysDateProperty, value); }
}

private static void TodaysDateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ((DateRangeSelectorControl)d).TodaysDateChanged((DateTime)e.NewValue);
}

private void TodaysDateChanged(DateTime newDate)
{
    //update your control here
}

然后,您的ViewModel可以简单地公开可以绑定到此DependencyProperty的TodaysDate属性。