【问题标题】:How to bind a command and data in a single control?如何在单个控件中绑定命令和数据?
【发布时间】:2014-09-13 21:18:00
【问题描述】:

我正在为一个项目编写自定义控件。该控件将包含一个下拉组合框和一个数据网格。此控件将在整个项目中使用。在控件上,我将 SelectedDate 和 SelectedDateChangedCommand 公开为依赖属性。当用户选择一个日期时,主程序模型将更新其相关日期的信息列表。

当我在项目中使用该控件时,数据 (SelectedDate) 应该来自模型,但命令 (SelectedDateChangedCommand) 应该来自 ViewModel。如何将数据绑定到模型,将命令绑定到视图模型?

基本上,如果我想绑定同一个按钮的内容和命令,我该怎么办?

编辑: 好吧,我不认为我解释得很好。我没有使用框架或模板或类似的东西。也许我的问题是提到 UserControl。我的问题不在于编写 UserControl。我的问题来自控制之外。我没有代码示例,因为这是我的问题:我该怎么做?如果我有某种代码,它会是这样的:

<Button Content="{Binding Model.SelectedDate]" Command="{Binding ViewModel.SelectedDateChanged}" />

如何在一个控件上绑定两个不同类的两个属性?

哇,在 WPF 中甚至 提问 问题也很困难。 :)

【问题讨论】:

  • 如何为命令参数添加另一个 DP,例如 WPF 的 Button.CommandParameter
  • 嗨,您是否正在使用代码隐藏(dp)创建用户控件,同时使用视图模型作为数据上下文?或者您是否创建了自定义控件?能否请您发布您的代码?
  • @Stígandr 我希望上述编辑有所帮助。我正在创建(我希望是)一个独立的自定义控件。我在我的项目中使用该控件来显示数据。想想按钮的内容和命令。你如何绑定这两者?
  • @TomPadilla 你能发布你的 xaml 和 .cs 吗?起初我这样做有点老套,在 cc 模板中的控件中绑定一个命令,然后调用一个暴露并绑定到你的 vm 的新命令。我已经摆脱了这一点,而是使用控件直接在 OnApplyTemplate 中抓取它们,然后基本上只需将命令从 cc 发送到 vm。无论如何,如果您发布您的代码,它将帮助我们帮助您 =)

标签: c# asp.net-mvc wpf data-binding user-controls


【解决方案1】:

好的,如果我理解你的话,你想创建一个抄送。然后在你的虚拟机上运行绑定到日期时间到你的 SelectedDate,并从控件调用一个命令到虚拟机?我在这里为你做了一个简单的例子,希望我理解正确。我只使用日期选择器简化了这个例子。我在这里使用galasoft MVVM Light。将内容更改为您想要的内容。希望我没有完全误解你的意思:)

Generic.xaml

<Style TargetType="{x:Type local:YourCustControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:YourCustControl}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <Grid >
                        <DatePicker x:Name="PART_DatePicker"
                           SelectedDate="{Binding Path=YourDateTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, 
                            RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:YourCustControl}}}"/>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

CustControl

[TemplatePart(Name = "PART_DatePicker", Type = typeof (DatePicker))]
public class YourCustControl : Control
{
    public static readonly DependencyProperty SelectedDateChangedCommandProperty = DependencyProperty.Register("SelectedDateChangedCommand", typeof (ICommand), typeof (YourCustControl), new PropertyMetadata(null));
    public static readonly DependencyProperty YourDateTimeProperty = DependencyProperty.Register("YourDateTime", typeof (DateTime), typeof (YourCustControl), new PropertyMetadata(null));
    private DatePicker datePicker;

    static YourCustControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof (YourCustControl), new FrameworkPropertyMetadata(typeof (YourCustControl)));
    }

    public ICommand SelectedDateChangedCommand
    {
        get { return (ICommand) GetValue(SelectedDateChangedCommandProperty); }
        set { SetValue(SelectedDateChangedCommandProperty, value); }
    }

    public DateTime YourDateTime
    {
        get { return (DateTime) GetValue(YourDateTimeProperty); }
        set { SetValue(YourDateTimeProperty, value); }
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        datePicker = (DatePicker) Template.FindName("PART_DatePicker", this);
        if (datePicker != null)
        {
            datePicker.SelectedDateChanged += datePicker_SelectedDateChanged;
        }
    }

    private void datePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
    {
        // Execute the command
        if (SelectedDateChangedCommand != null && SelectedDateChangedCommand.CanExecute(e) && !e.Handled)
            SelectedDateChangedCommand.Execute(e);
    }
}

视图模型

// replace with whatever, like extend Galasoft's ViewModelBase 
public class YourViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator] // Remove if no R#
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class YourViewModel : YourViewModelBase
{
    private DateTime dateTime;

    public DateTime DateTime
    {
        get { return dateTime; }
        set
        {
            if (value.Equals(dateTime)) return;
            dateTime = value;
            OnPropertyChanged();
        }
    }

    public ICommand SelectedDateChangedCommand { get; set; }

    public YourViewModel()
    {
        SelectedDateChangedCommand = new RelayCommand<SelectionChangedEventArgs>(OnSelectedDateChanged);
    }

    private void OnSelectedDateChanged(SelectionChangedEventArgs e)
    {
        if (e != null)
            e.Handled = true; // dirty hack
        // do stuff here
    }
}

终于是你的 xaml

<Grid>
    <local:YourCustControl SelectedDateChangedCommand="{Binding SelectedDateChangedCommand}" 
                           YourDateTime="{Binding DateTime, Mode=TwoWay}"/>
</Grid>

希望对你有帮助!

干杯

【讨论】:

  • 好的,我没有使用模板或类似的东西(我的 UserControl 比模板可以处理的要复杂得多)。而且我没有使用 MVVM 框架或任何东西。但是我看到您在 ViewModel 上都有 DateTime 和 SelectedDateChangedCommand。这是正确的方法吗? DateTime 不应该在模型上吗?而且,如果是,如何同时绑定 Model 上的 DateTime 和 ViewModel 上的 SelectedDateChangedCommand?
猜你喜欢
  • 2019-10-04
  • 2014-01-16
  • 1970-01-01
  • 2011-12-01
  • 1970-01-01
  • 2013-01-17
  • 2015-04-06
  • 1970-01-01
  • 2010-12-17
相关资源
最近更新 更多