在另一个视图模型中执行命令

本文关键字:执行 命令 模型 另一个 视图 | 更新日期: 2023-09-27 17:59:57

我有一个从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",旨在每当系统日期更改时更新此控件中的"Today"筛选器,并绑定到"ActivityListMenuControlViewModel"中的命令"Today DateUpdatedCommand"
更新日期的代码在"DateRangeSelector"本身的方法"SetDateValues"中。我只是困惑于如何从"ActivityListMenuControlViewModel"中执行此方法?请帮忙。

更新:DateRangeSelector只是一个没有视图/视图模型的类。这是代码:

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"和命令属性"Today DateUpdatedCmd",该属性在"ActivityListMenuControlView.xaml"中使用,如xaml片段中所示。此外,我需要在DateRangeSelector类中执行方法"SetDateValues"来更新今天的日期。现在请帮我弄清楚如何做到这一点?

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

"对与指定绑定约束匹配的类型"VMS.Nexus.Client.Common.Controls.DateRangeSelectorControl"的构造函数调用引发异常。"行号为'45',行位置为'14'。"}

内部异常:{"默认值类型与属性"TodayDate"的类型不匹配。"}

在我创建DateRangeSelector的ActivityListMenuControlView.xaml中引发了此异常。请帮助

在另一个视图模型中执行命令

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

如果您的控件需要对某个变化的变量做出反应,那么它应该公开一个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属性。

在编写WPF和MVVM时,开发人员通常会使用我们可以在视图模型中声明的delegate ICommand形式。您可以在MSDN上的WPF Apps With the Model View ViewModel Design Pattern页面的Relaying Command Logic部分中找到流行的RelayCommand的实现细节。你可以在wpf中的How can I use the RelayCommand中找到它使用的基本示例?关于Stack Overflow的问题。

因此,您可以在视图模型中定义ICommand实例,并将它们数据绑定到控件。在您的DateRangeSelector的情况下,您可以简单地声明ICommand类型的DependencyProperty,并从视图模型中数据绑定到它。。。也许是这样的:

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

在你看来,模型是:

public ICommand Command
{
    get { return new ActionCommand(action => DoSomething(),
        canExecute => CanDoSomething(); }
}

更新>>>

简单地说,不需要在WPF中的这个(或几乎任何)实例中扩展ComboBox类。请参阅MSDN上的Control Authoring Overview页面,了解为什么不需要这样做的更多信息。

因此,基本的想法是,将功能从ComboBox转移到另一个类。。。视图模型类。从那里,您可以将数据绑定到ComboBox并提供功能。在WPF中,我们操作数据,而不是UIElements。因此,与其在控件中定义所有"过滤器",不如在代码中定义它们。

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

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();
    }
}

private void FillAvailableDatesDependantOnFilterType()
{
    AvailableDates = new ObservableCollection<DateTime>();
    if (FilterType == "Today") AvailableDates.Add(DateTime.Now.Date);
    ...
}

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