在另一个视图模型中执行命令
本文关键字:执行 命令 模型 另一个 视图 | 更新日期: 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);
...
}
希望你现在有一个更好的主意。