如何使用静态事件将附加行为的信息传递给viewmodel?

时间:2015-08-08 18:51:14

标签: c# wpf mvvm

我在视图中有一个附加属性到文本框。附加属性对文本框输入执行验证并执行其他杂务。附加的属性验证例程引发了一个由viewmodel监视的事件。

  1. 通过让viewmodel获取无效的TextBox,这会“违反”MVVM推理吗?
  2. 当删除包含文本框的用户控件时,GC如何处理附加属性的静态事件?
  3. 如果需要特定的代码来避免内存泄漏,那怎么办?
  4. 有没有首选的方法呢?
  5. 对于长长的列表感到抱歉,但Google没有解决这种情况。

    感谢任何和所有帮助。谢谢你的考虑。

    (VS2010 .net 4.5)

    TIA

    视图模型

    class CheckInViewModel : SimpleViewModelBase
        {
            public CheckInViewModel()
            {
                InValidTextBoxes = new List<TextBox>();
    
                Stargate_V.Helpers.ColorMaskingTextBoxBehavior.Validated += (sender, e) =>
                    {
                        if (e.valid)
                            InValidTextBoxes.Remove(e.sender);
                        else
                            InValidTextBoxes.Add(e.sender);
                    };
            }
    
            List<TextBox> InValidTextBoxes;
    
    
        }
    

    XAML

     <TextBox 
                h:ColorMaskingTextBoxBehavior.Mask="^[MmFf]$"
                Text="{Binding Sex}"
                Height="24" HorizontalAlignment="Right" Margin="0,55,665,0" VerticalAlignment ="Top" Width="36" />
    

    附加的繁荣

      public class ColorMaskingTextBoxBehavior : DependencyObject
        {
            // Entrance point from Xaml 
            public static readonly DependencyProperty MaskProperty = DependencyProperty.RegisterAttached("Mask",
                    typeof(string),
                    typeof(ColorMaskingTextBoxBehavior),
                    new FrameworkPropertyMetadata(OnMaskChanged));
    ...........................
    
     // Callback from XAML initialization of the attached property.
        private static void OnMaskChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            var textBox = dependencyObject as TextBox;
            var mask = e.NewValue as string;
            textBox.PreviewTextInput -= textBox_PreviewTextInput;
            textBox.PreviewKeyDown -= textBox_PreviewKeyDown;
            DataObject.RemovePastingHandler(textBox, Pasting);
            DataObject.RemoveCopyingHandler(textBox, NoDragCopy);
            CommandManager.RemovePreviewExecutedHandler(textBox, NoCutting);
    
    
            if (mask == null)
            {
                textBox.ClearValue(MaskProperty);
                textBox.ClearValue(MaskExpressionProperty);
            }
            else
            {
                textBox.SetValue(MaskProperty, mask);
                SetMaskExpression(textBox, new Regex(mask, RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace));
                textBox.PreviewTextInput += textBox_PreviewTextInput;
                textBox.PreviewKeyDown += textBox_PreviewKeyDown;
                DataObject.AddPastingHandler(textBox, Pasting);
                DataObject.AddCopyingHandler(textBox, NoDragCopy);
                CommandManager.AddPreviewExecutedHandler(textBox, NoCutting);
            }
        }
    
    
    
    private static void textBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
            {
                var textBox = sender as TextBox;
                var maskExpression = GetMaskExpression(textBox);
    
                string passHex = (string)textBox.GetValue(PassColorProperty);
                string failHex = (string)textBox.GetValue(FailColorProperty);
                Color passColor = Extensions.ToColorFromHex(passHex);
                Color failColor = Extensions.ToColorFromHex(failHex);
    
                if (maskExpression == null)
                {
                    return;
                }
    
                var proposedText = GetProposedText(textBox, e.Text);
    
                if (!maskExpression.IsMatch(proposedText))
                {
                    textBox.Background = new SolidColorBrush(failColor);
    
                    ValidationEventArgs args = new ValidationEventArgs();
                    args.sender = textBox;
                    args.valid = false;
                    OnValidation(args);
                }
                else
                {
                    textBox.Background = new SolidColorBrush(passColor);
    
                    ValidationEventArgs args = new ValidationEventArgs();
                    args.sender = textBox;
                    args.valid = true;
                    OnValidation(args);
                }
            }
    

    从上述代码中调用的事件

        public static event EventHandler<ValidationEventArgs> Validated;
    
        static void OnValidation(ValidationEventArgs e)
        {
            EventHandler<ValidationEventArgs> handler = Validated;
            if (handler != null)
            {
                handler(null, e);
            }
        }
    
    
    public class ValidationEventArgs : EventArgs
    {
        public TextBox sender;
        public bool valid;
    }
    

1 个答案:

答案 0 :(得分:3)

是的,我认为这违反了MVVM。您的视图模型应该不了解任何视图。总是问自己的问题是&#34;我可以在不创建任何视图的情况下运行我的应用程序吗?&#34;。在这种情况下,您的视图模型直接与TextBoxes列表进行交互,因此模式已被破坏。

在这里有几种实现目标的方法,最简单的方法是在视图模型中创建一个处理程序,当TextBox文本发生更改时,该处理程序会被调用:

public delegate void ValidationDelegate(bool isValid);

public class MyViewModel : ViewModelBase
{
    public ValidationDelegate ValidationHandler { get { return (isValid) => OnValidate(isValid); } }

    private void OnValidate(bool isValid)
    {
        // handle the validation event here
    }
}

现在您只需要一个带有附加属性的行为,您可以绑定到此处理程序:

public class ValidateBehavior : Behavior<TextBox>
{
    public ValidationDelegate Validated
    {
        get { return (ValidationDelegate)GetValue(ValidatedProperty); }
        set { SetValue(ValidatedProperty, value); }
    }

    public static readonly DependencyProperty ValidatedProperty =
        DependencyProperty.Register("Validated", typeof(ValidationDelegate), typeof(ValidateBehavior), new PropertyMetadata(null));

    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.TextChanged += ValidateText;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.TextChanged -= ValidateText;
    }

    private void ValidateText(object sender, TextChangedEventArgs e)
    {
        if (this.Validated != null)
        {
            bool isValid = true; // do text validation here
            this.Validated(isValid);
        }
    }
}

然后最后将行为添加到有问题的TextBox并绑定处理程序:

    <TextBox>
        <i:Interaction.Behaviors>
            <behaviors:ValidateBehavior Validated="{Binding ValidationHandler}"/>
        </i:Interaction.Behaviors>
    </TextBox>

编辑:如果您不想使用混合行为,那么您也可以使用附加行为来执行此操作:

public static class ValidateBehavior
{
    public static ValidationDelegate GetValidate(TextBox textbox)
    {
        return (ValidationDelegate)textbox.GetValue(ValidateProperty);
    }

    public static void SetValidate(TextBox textbox, ValidationDelegate value)
    {
        textbox.SetValue(ValidateProperty, value);
    }

    public static readonly DependencyProperty ValidateProperty =
        DependencyProperty.RegisterAttached(
        "Validate",
        typeof(ValidationDelegate),
        typeof(ValidateBehavior),
        new UIPropertyMetadata(null, OnValidateChanged));

    static void OnValidateChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        var textbox = depObj as TextBox;
        if (textbox == null)
            return;

        if (e.OldValue is ValidationDelegate)
            textbox.TextChanged -= OnTextChanged;

        if (e.NewValue is ValidationDelegate)
            textbox.TextChanged += OnTextChanged;
    }

    static void OnTextChanged(object sender, RoutedEventArgs e)
    {
        if (!Object.ReferenceEquals(sender, e.OriginalSource))
            return;

        var textbox = e.OriginalSource as TextBox;
        if (textbox != null)
        {
            var validate = GetValidate(textbox);
            if (validate != null)
            {
                bool isValid = true; // do text validation here
                validate(isValid);
            }
        }
    }
}

相应的XAML:

<TextBox behaviors:ValidateBehavior.Validate="{Binding ValidationHandler}" />