1

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

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

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

我该怎么做?在我看来,我必须以某种方式让方法的绑定像 OneWayToSource 一样工作。

我很抱歉,以防它重复。此外,提前感谢各位。

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

4

5 回答 5

3

我认为您可以在这里做的最简单的事情是公开一个bool属性,也许称为IsCleared,并在它变为真时从该属性调用您的方法。暴露ICommand和/或delegate对象会将功能转移到您无法控制的范围内,因此您无法使用它们。

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

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

如果你真的不喜欢boolswitch 的想法,那么enum房产呢?创建一个enum具有特定值的值ClearText以及您想要公开的任何其他功能。然后其他开发人员只需将此属性设置为相关实例以实例化该功能......我只建议使用boolswitch 属性,因为它看起来好像您只想公开一个功能。

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

public bool IsTextClear
{
    get { if (value) ClearText(); }
}
于 2013-09-11T10:54:20.947 回答
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 时。属性更改将在控制中触发并引用它。

于 2013-09-11T10:45:48.600 回答
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));
    }
}
于 2013-09-11T18:49:47.637 回答
-1

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

于 2013-09-20T18:42:15.317 回答
-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;
}

在您的视图模型中:

public ICommand Command { get; set; }

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

<Button Click="{Binding Command}" />
于 2013-09-11T10:34:37.170 回答