【问题标题】:Changing the property of a xaml button from another xaml从另一个 xaml 更改 xaml 按钮的属性
【发布时间】:2015-08-21 17:31:05
【问题描述】:

我是 Silverlight 和 MVVM 的新手,我正在尝试从应用程序内的另一个 xaml 更改一个 xaml 的 Button.IsEnabled

我尝试创建一个类,但我不确定我是否正确使用它...

using System.ComponentModel;

namespace Reporting.Models
{
public class DataSourceValidation : INotifyPropertyChanged
{
    private bool _isSaveEnabled;

    public bool IsSaveEnabled
    {
        get
        {
            return _isSaveEnabled;
        }
        set
        {
            _isSaveEnabled = value;
            RaisedPropertyChanged("IsSaveEnabled");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisedPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }
}

}

非常感谢您的解释和示例。我一直在寻找,但它并没有完全了解如何将控件绑定到模型,然后从另一个 xaml.cs 更改该值...前提是我什至以正确的方式考虑这一点。

如果我需要提供更多信息,请询问。感谢您的宝贵时间。

【问题讨论】:

    标签: c# xaml silverlight mvvm


    【解决方案1】:

    如果您只是不想快速完成它(没有好的解决方案),那么您可以使用静态属性来实现:

    ExampleA.xaml.cs 中创建以下属性:

    public static ExampleA CurrentInstance { get; private set; }
    

    ExampleA的构造函数中(我假设类的名字是ExampleA):

    public ExampleA()
    {
        this.InitializeComponent();
        CurrentInstance = this;
    }
    

    然后在你的ExampleBLostFocus 方法中:

    if (ExampleA.CurrentInstance != null)
    {
         var button = ExampleA.CurrentInstance.FindName("OKButton") as Button;
         if (button != null)
         {
             button.IsEnabled = true;
         }
    }
    

    另一方面,我不知道您的类的结构以及这些 XAML 文件之间的关系,但一个好的通用解决方案是使用 Event Aggregator 模式:

    我在这里使用来自Caliburn.Micro MVVM 框架的EventAggregator 类的略微修改版本:

    namespace Caliburn.Micro
    {
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Reflection;
    
        /// <summary>
        ///   A marker interface for classes that subscribe to messages.
        /// </summary>
        public interface IHandle { }
    
        /// <summary>
        ///   Denotes a class which can handle a particular type of message.
        /// </summary>
        /// <typeparam name = "TMessage">The type of message to handle.</typeparam>
        public interface IHandle<TMessage> : IHandle
        {
            /// <summary>
            ///   Handles the message.
            /// </summary>
            /// <param name = "message">The message.</param>
            void Handle(TMessage message);
        }
    
        /// <summary>
        ///   Enables loosely-coupled publication of and subscription to events.
        /// </summary>
        public interface IEventAggregator
        {
            /// <summary>
            ///   Gets or sets the default publication thread marshaller.
            /// </summary>
            /// <value>
            ///   The default publication thread marshaller.
            /// </value>
            Action<System.Action> PublicationThreadMarshaller { get; set; }
    
            /// <summary>
            ///   Subscribes an instance to all events declared through implementations of <see cref = "IHandle{T}" />
            /// </summary>
            /// <param name = "instance">The instance to subscribe for event publication.</param>
            void Subscribe(object instance);
    
            /// <summary>
            ///   Unsubscribes the instance from all events.
            /// </summary>
            /// <param name = "instance">The instance to unsubscribe.</param>
            void Unsubscribe(object instance);
    
            /// <summary>
            ///   Publishes a message.
            /// </summary>
            /// <param name = "message">The message instance.</param>
            /// <remarks>
            ///   Uses the default thread marshaller during publication.
            /// </remarks>
            void Publish(object message);
    
            /// <summary>
            ///   Publishes a message.
            /// </summary>
            /// <param name = "message">The message instance.</param>
            /// <param name = "marshal">Allows the publisher to provide a custom thread marshaller for the message publication.</param>
            void Publish(object message, Action<System.Action> marshal);
        }
    
        /// <summary>
        ///   Enables loosely-coupled publication of and subscription to events.
        /// </summary>
        public class EventAggregator : IEventAggregator
        {
    
            /// <summary>
            /// The singleton instance.
            /// </summary>
            public static EventAggregator Instance = new EventAggregator();
    
            /// <summary>
            ///   The default thread marshaller used for publication;
            /// </summary>
            public static Action<System.Action> DefaultPublicationThreadMarshaller = action => action();
    
            readonly List<Handler> handlers = new List<Handler>();
    
            /// <summary>
            ///   Initializes a new instance of the <see cref = "EventAggregator" /> class.
            /// </summary>
            public EventAggregator()
            {
                PublicationThreadMarshaller = DefaultPublicationThreadMarshaller;
            }
    
            /// <summary>
            ///   Gets or sets the default publication thread marshaller.
            /// </summary>
            /// <value>
            ///   The default publication thread marshaller.
            /// </value>
            public Action<System.Action> PublicationThreadMarshaller { get; set; }
    
            /// <summary>
            ///   Subscribes an instance to all events declared through implementations of <see cref = "IHandle{T}" />
            /// </summary>
            /// <param name = "instance">The instance to subscribe for event publication.</param>
            public virtual void Subscribe(object instance)
            {
                lock (handlers)
                {
                    if (handlers.Any(x => x.Matches(instance)))
                        return;
    
                    handlers.Add(new Handler(instance));
                }
            }
    
            /// <summary>
            ///   Unsubscribes the instance from all events.
            /// </summary>
            /// <param name = "instance">The instance to unsubscribe.</param>
            public virtual void Unsubscribe(object instance)
            {
                lock (handlers)
                {
                    var found = handlers.FirstOrDefault(x => x.Matches(instance));
    
                    if (found != null)
                        handlers.Remove(found);
                }
            }
    
            /// <summary>
            ///   Publishes a message.
            /// </summary>
            /// <param name = "message">The message instance.</param>
            /// <remarks>
            ///   Does not marshall the the publication to any special thread by default.
            /// </remarks>
            public virtual void Publish(object message)
            {
                Publish(message, PublicationThreadMarshaller);
            }
    
            /// <summary>
            ///   Publishes a message.
            /// </summary>
            /// <param name = "message">The message instance.</param>
            /// <param name = "marshal">Allows the publisher to provide a custom thread marshaller for the message publication.</param>
            public virtual void Publish(object message, Action<System.Action> marshal)
            {
                Handler[] toNotify;
                lock (handlers)
                    toNotify = handlers.ToArray();
    
                marshal(() =>
                {
                    var messageType = message.GetType();
    
                    var dead = toNotify
                        .Where(handler => !handler.Handle(messageType, message))
                        .ToList();
    
                    if (dead.Any())
                    {
                        lock (handlers)
                        {
                            foreach (var handler in dead)
                            {
                                handlers.Remove(handler);
                            }
                        }
                    }
                });
            }
    
            protected class Handler
            {
                readonly WeakReference reference;
                readonly Dictionary<Type, MethodInfo> supportedHandlers = new Dictionary<Type, MethodInfo>();
    
                public Handler(object handler)
                {
                    reference = new WeakReference(handler);
    
                    var interfaces = handler.GetType().GetInterfaces()
                        .Where(x => typeof(IHandle).IsAssignableFrom(x) && x.IsGenericType);
    
                    foreach (var @interface in interfaces)
                    {
                        var type = @interface.GetGenericArguments()[0];
                        var method = @interface.GetMethod("Handle");
                        supportedHandlers[type] = method;
                    }
                }
    
                public bool Matches(object instance)
                {
                    return reference.Target == instance;
                }
    
                public bool Handle(Type messageType, object message)
                {
                    var target = reference.Target;
                    if (target == null)
                        return false;
    
                    foreach (var pair in supportedHandlers)
                    {
                        if (pair.Key.IsAssignableFrom(messageType))
                        {
                            pair.Value.Invoke(target, new[] { message });
                            return true;
                        }
                    }
    
                    return true;
                }
            }
        }
    }
    

    在你的项目中复制这个类。

    然后创建一个简单的消息类,它将向任何侦听器表示需要启用按钮的消息:

    public class EnableButtonMessage
    {
    }
    

    然后你的ExampleA 类需要实现IHandle&lt;EnableButtonMessage&gt; 接口(在构造函数中你需要订阅这个类正在接收某种消息,并且Handle 方法在注册类型的实际消息时执行收到您然后启用按钮):

    public sealed class ExampleA : UserControl, IHandle<EnableButtonMessage>
    {
        ...
        public ExampleA()
        {
            this.InitializeComponent();
            EventAggregator.Instance.Subscribe(this);
        }
        ...
        public void Handle(EnableButtonMessage message)
        {
            this.OKButton.IsEnabled = true;
        }
        ...
    }
    

    ExampleB class'LostFocus 方法中,您只需调用即可更改按钮属性:

    EventAggregator.Instance.Publish(new EnableButtonMessage());
    

    这是EventAggregator 模式的简单实现,然后您可以将 if 用于全局应用程序内部任何实体之间的任何消息传递。这是一种强大的模式,当与 MVVM 一起使用时,可以让您的生活变得更轻松。

    【讨论】:

      猜你喜欢
      • 2015-07-01
      • 2017-07-19
      • 2015-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-29
      • 1970-01-01
      相关资源
      最近更新 更多