具有OneWayToSource模式的“可绑定方法”

时间:2013-09-11 10:27:54

标签: c# wpf

我需要编写一个看起来像TextBox的自定义控件,它包含一个名为Refresh()的方法,其主要目的是清除Text并回滚其他一些值。

该方法将以某种方式变为可绑定,以便其他人可以使用它来绑定ViewModel中的属性。因此,为什么我认为在我的自定义控件中我将需要一个Action类型的依赖项属性。

到目前为止如此逻辑但下一个问题是一旦用户在其上设置双向绑定,方法/ dp可能无法在控制端被覆盖。基本上我总是必须将方法包装器作为Action传递给ViewModel,而在ViewModel中,其他用户可以调用它。

我该怎么做?在我看来,我必须以某种方式获得方法的绑定工作,如OneWayToSource。

我道歉,以防它重复。此外还要感谢先生们。

编辑:请不要替代解决方案。这些是要求,我必须坚持下去。

5 个答案:

答案 0 :(得分:3)

我认为你在这里做的最简单的事情就是暴露一个bool属性,也许叫做IsCleared,并且当它成为真时,只需从该属性调用你的方法。公开ICommand和/或delegate个对象会将功能转移出您的控件,因此您无法使用这些功能。

@ninjahedgehog,为什么你不能使用bool'switch'属性?您的要求是“以便其他人可以将ViewModel中的属性与它绑定”......他们可以从其视图模型绑定到bool属性。在我看来,似乎是你唯一的选择。正如我之前所说,您不能使用ICommand和/或delegate对象,因为这会将功能转移到您的控制之外 - 这将使其他开发人员能够编写自己的功能而不是仅仅调用你的。

你真正想要的是一个控制方法,他们可以从他们的视图模型调用...但是视图模型不应该对视图控件有任何了解,所以你不能这样做。接下来最好的事情是创建一个在给定属性值时调用的方法。在这里你有几个选择。

如果确实不喜欢bool切换提示,那么enum属性怎么样?创建一个enum,其中包含ClearText等特定值以及您希望公开的其他功能。然后其他开发人员只需将此属性设置为相关实例以实例化该功能......我只建议bool开关属性,因为它似乎只是想要公开一个功能。

关于使用bool开关属性的最后一点要注意......因为它是一个开关,你需要在使用后重置它,或者只是从不实际设置它:

public bool IsTextClear
{
    get { if (value) ClearText(); }
}

答案 1 :(得分:1)

我不知道为什么你需要这个因为使用你的控件的人可以直接从后面的代码调用方法。但是如果你想要控制时应该有一些像ClearMe这样的属性,当设置为true时它应该清除控件然后你可以定义依赖属性并听取它在控制中的变化,如下所示,并从那里调用Refresh。

    public static readonly DependencyProperty ClearMeProperty = DependencyProperty.Register
        (
             "ClearMe",
             typeof(bool),
             typeof(MyControl),
             new FrameworkPropertyMetadata(false, OnClearMeChanged)
        );

        public bool ClearMe
        {
            get { return (bool)GetValue(ClearMeProperty); }
            set { SetValue(ClearMeProperty, value); }
        }

        private static void OnClearMeChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
           var control = sender as MyControl;
           if((bool)e.NewValue)
           {
               control.Refresh()
           }
        }

您可以将此属性绑定到ViewModel属性。每当ViewModel属性更改为true时。财产变更将在控制权中解雇,并将其转介。

答案 2 :(得分:1)

我编辑了我的答案,因为我不理解你想要什么。我能想出你想要的唯一方法是在CustomControl上使用Action DependencyProperty并使用OneWayToSource绑定将其绑定到ViewModel,这样来自控件的Action就会被发送到viewmodel。在你的自定义控件中,你可以测试以确保只使用OneWayToSource绑定,如果没有则执行某些操作..在这种情况下,我添加一些文本并使背景变为红色。

查看

<UserControl x:Class="WpfApplication1.Views.TestView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:vm="clr-namespace:WpfApplication1.ViewModels"
         xmlns:controls="clr-namespace:WpfApplication1.Controls">      
<UserControl.Resources>
    <vm:TestViewModel x:Key="TestViewModel" />
</UserControl.Resources>

<StackPanel DataContext="{StaticResource TestViewModel}">
    <StackPanel Orientation="Horizontal" Height="30">
        <controls:CustomTextBox Width="300" Refresh="{Binding RefreshAction, Mode=OneWayToSource}"  />
        <Button Content="Refresh" Width="80" Command="{Binding RefreshFromView}" />
    </StackPanel>
</StackPanel>

视图模型

using System;
using System.ComponentModel;

namespace WpfApplication1.ViewModels
{
    public class TestViewModel : INotifyPropertyChanged
    {
        public TestViewModel()
        {
            RefreshFromView = new RelayCommand(ExecuteRefreshFromView);
        }

        public Action RefreshAction { get; set; }

        public RelayCommand RefreshFromView { get; set; }
        private void ExecuteRefreshFromView(object parameter)
        {
            if (RefreshAction != null)
                RefreshAction();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyOfPropertyChange(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

自定义控制

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace WpfApplication1.Controls
{
    public class CustomTextBox : TextBox
    {
        public CustomTextBox()
        {
            this.Loaded += CustomTextBox_Loaded;
        }

        void CustomTextBox_Loaded(object sender, RoutedEventArgs e)
        {
            BindingExpression bindingExpression = GetBindingExpression(RefreshProperty);
            BindingMode mode = bindingExpression.ParentBinding.Mode;

            if (mode != BindingMode.OneWayToSource)
            {
                Text = "Use OneWayToSource Binding only!";
                Background = new SolidColorBrush(Colors.Red);
            }

            Refresh = new Action(DoRefresh);
        }

        private void DoRefresh()
        {
            Text = null;
        }

        public Action Refresh
        {
            get { return (Action)GetValue(RefreshProperty); }
            set { SetValue(RefreshProperty, value); }
        }

        public static readonly DependencyProperty RefreshProperty = DependencyProperty.Register("Refresh", typeof(Action), typeof(CustomTextBox));
    }
}

答案 3 :(得分:0)

解决了另一个论坛解决方案将在博客条目中发布

答案 4 :(得分:-1)

您可以使用命令:

public class Command : ICommand
{
    public void Execute(object parameter)
    {
        // Do whatever you have to do
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;
}

在ViewModel中:

public ICommand Command { get; set; }

在您的XAML中(假设您的自定义控件由TextBox和Button组成):

<Button Click="{Binding Command}" />