Wpf 沿VisualTree发送通知

Wpf 沿VisualTree发送通知,wpf,Wpf,如何在可视树下发送通知 下面是一个简单的代码示例: class MyButton1 : Button { .... } Generic.XAML如下所示: <Style TargetType="{x:Type local:MyButton1}"> <Setter Property="Template"> <Setter.Value> <C

如何在可视树下发送通知

下面是一个简单的代码示例:

class MyButton1 : Button
{
 ....
}
Generic.XAML如下所示:

         <Style TargetType="{x:Type local:MyButton1}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:MyButton1}">
                        <Button>
                           <StackPanel>
                             <Label>
                              <local:MyTextBlock1 Text="Not working yet."/>
                             </Label>
                            </StackPanel>
                        </Button>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
public class Person
{
  private proeprty _firstName;
  public property FirstName
  {
    get
    {
      return _firstName;
    }
    set
    {
      _firstName = value;
      NotifyPropertyChanged("FirstName"); // This is required to notify the UI. Specific implementation will depend on your property notification pattern.
    }
  }

没有VIEWMODEL。它是一个自定义控件,当单击MyButton1时,它应该通知MyTextBlock1将文本更改为“它正在工作”。MyButton1位于可视树的顶层,MyTextblock1位于底层的某个地方


那么,如何在可视化树中发送通知并在特定元素中处理它们呢?。在我的例子中,它的MyButton1和单击时,通知应该沿着可视树向下移动,直到MyTextBlock1。然后应该处理通知并将文本更改为“It is working”。

在使用WPF开发时,您应该考虑使用,并为您提供许多现成的功能

在MVVM模式中,您将拥有一个viewmodel,它是视图的数据上下文。您的视图将包含两个文本框和按钮

MVVM框架将提供一些机制,用于在单击按钮时调用viewmodel上的方法

viewmodel将公开绑定到视图上两个文本框的两个公共字符串属性。单击按钮时,将调用viewmodel方法,该方法设置2个字符串属性的值,然后通过WPF数据绑定更新文本框中的文本


这是一个概念,但我会先阅读一下MVVM,然后再比较一下MVVM框架。

在使用WPF开发时,您应该考虑使用,并为您提供许多现成的功能

在MVVM模式中,您将拥有一个viewmodel,它是视图的数据上下文。您的视图将包含两个文本框和按钮

MVVM框架将提供一些机制,用于在单击按钮时调用viewmodel上的方法

viewmodel将公开绑定到视图上两个文本框的两个公共字符串属性。单击按钮时,将调用viewmodel方法,该方法设置2个字符串属性的值,然后通过WPF数据绑定更新文本框中的文本

这就是概念,但我会先阅读一下MVVM,然后再比较一下MVVM框架。

代码隐藏示例

在您的xaml中

<Button Click="Button_Click_1">Click me</Button>
<TextBox Name="myTextBox" HorizontalAlignment="Stretch" />
基本上,这个概念是,如果给控件命名,可以通过直接调用名称在代码隐藏中操纵其属性,如我的示例所示。

代码隐藏示例

在您的xaml中

<Button Click="Button_Click_1">Click me</Button>
<TextBox Name="myTextBox" HorizontalAlignment="Stretch" />

基本上,这个概念是,如果给控件命名,可以通过直接调用名称在代码中操纵其属性,如我的示例所示。

MVVM和数据绑定示例

我的简单人课程

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
我的简单PersonViewModel类

public class PersonViewModel : INotifyPropertyChanged
{
    public PersonViewModel(Person person)
    {
        if (person == null)
            throw new ArgumentNullException("person");
        this.Model = person;

        this.ShowFirstNameCommand = new DelegateCommand((o) => this.showFirstName());
        this.ShowLastNameCommand = new DelegateCommand((o) => this.showLastName());
    }

    public ICommand ShowFirstNameCommand { get; private set; }
    public ICommand ShowLastNameCommand { get; private set; }

    public Person Model { get; private set; }

    public string FirstName
    {
        get
        {
            return this.Model.FirstName;
        }
        set
        {
            this.Model.FirstName = value;
            this.OnPropertyChanged("FirstName");
        }
    }

    public string LastName
    {
        get
        {
            return this.Model.LastName;
        }
        set
        {
            this.Model.LastName = value;
            this.OnPropertyChanged("LastName");
        }
    }

    private string _showString;

    public string ShowString
    {
        get
        {
            return this._showString;
        }
        set
        {
            this._showString = value;
            this.OnPropertyChanged("ShowString");
        }
    }

    private void showFirstName()
    {
        this.ShowString = this.FirstName;
    }

    private void showLastName()
    {
        this.ShowString = this.LastName;
    }

    #region INPC code - can create an abstract base view model class and put this there instead

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    #endregion
}
DelegateCommand类使按钮命令工作

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System;
using System.Windows.Input;

namespace WpfApplication1
{
public class DelegateCommand : ICommand
{
    /// <summary>
    /// Action to be performed when this command is executed
    /// </summary>
    private Action<object> executionAction;

    /// <summary>
    /// Predicate to determine if the command is valid for execution
    /// </summary>
    private Predicate<object> canExecutePredicate;

    /// <summary>
    /// Initializes a new instance of the DelegateCommand class.
    /// The command will always be valid for execution.
    /// </summary>
    /// <param name="execute">The delegate to call on execution</param>
    public DelegateCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Initializes a new instance of the DelegateCommand class.
    /// </summary>
    /// <param name="execute">The delegate to call on execution</param>
    /// <param name="canExecute">The predicate to determine if command is valid for execution</param>
    public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
        {
            throw new ArgumentNullException("execute");
        }

        this.executionAction = execute;
        this.canExecutePredicate = canExecute;
    }

    /// <summary>
    /// Raised when CanExecute is changed
    /// </summary>
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    /// <summary>
    /// Executes the delegate backing this DelegateCommand
    /// </summary>
    /// <param name="parameter">parameter to pass to predicate</param>
    /// <returns>True if command is valid for execution</returns>
    public bool CanExecute(object parameter)
    {
        return this.canExecutePredicate == null ? true : this.canExecutePredicate(parameter);
    }

    /// <summary>
    /// Executes the delegate backing this DelegateCommand
    /// </summary>
    /// <param name="parameter">parameter to pass to delegate</param>
    /// <exception cref="InvalidOperationException">Thrown if CanExecute returns false</exception>
    public void Execute(object parameter)
    {
        if (!this.CanExecute(parameter))
        {
            throw new InvalidOperationException("The command is not valid for execution, check the CanExecute method before attempting to execute.");
        }
        this.executionAction(parameter);
        }
    }
}
基本上我在屏幕上显示两个按钮和一个文本框。其中一个按钮在单击时将在文本框中显示此人的名字,另一个按钮将在同一文本框中显示此人的姓氏。如果您检查代码,您将看到我使用WPF命令实现了这一点。按钮的命令属性绑定到我的PersonViewModel类的ICommand属性。然后将这些属性“绑定”(使用DelegateCommand)到同一viewmodel类中的私有方法。我还有一个公共ShowString属性,它是绑定到屏幕上文本框的数据,用于控制文本框中显示的字符串。您将看到viewmodel类中的my private方法更改此ShowString属性的值,以更改文本框中显示的数据

我的xaml代码与您的不同(您没有提供代码),但是这个概念应该适合您


希望这能有所帮助。

MVVM和数据绑定示例

我的简单人课程

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
我的简单PersonViewModel类

public class PersonViewModel : INotifyPropertyChanged
{
    public PersonViewModel(Person person)
    {
        if (person == null)
            throw new ArgumentNullException("person");
        this.Model = person;

        this.ShowFirstNameCommand = new DelegateCommand((o) => this.showFirstName());
        this.ShowLastNameCommand = new DelegateCommand((o) => this.showLastName());
    }

    public ICommand ShowFirstNameCommand { get; private set; }
    public ICommand ShowLastNameCommand { get; private set; }

    public Person Model { get; private set; }

    public string FirstName
    {
        get
        {
            return this.Model.FirstName;
        }
        set
        {
            this.Model.FirstName = value;
            this.OnPropertyChanged("FirstName");
        }
    }

    public string LastName
    {
        get
        {
            return this.Model.LastName;
        }
        set
        {
            this.Model.LastName = value;
            this.OnPropertyChanged("LastName");
        }
    }

    private string _showString;

    public string ShowString
    {
        get
        {
            return this._showString;
        }
        set
        {
            this._showString = value;
            this.OnPropertyChanged("ShowString");
        }
    }

    private void showFirstName()
    {
        this.ShowString = this.FirstName;
    }

    private void showLastName()
    {
        this.ShowString = this.LastName;
    }

    #region INPC code - can create an abstract base view model class and put this there instead

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }

    #endregion
}
DelegateCommand类使按钮命令工作

// Copyright © Microsoft Corporation.  All Rights Reserved.
// This code released under the terms of the 
// Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

using System;
using System.Windows.Input;

namespace WpfApplication1
{
public class DelegateCommand : ICommand
{
    /// <summary>
    /// Action to be performed when this command is executed
    /// </summary>
    private Action<object> executionAction;

    /// <summary>
    /// Predicate to determine if the command is valid for execution
    /// </summary>
    private Predicate<object> canExecutePredicate;

    /// <summary>
    /// Initializes a new instance of the DelegateCommand class.
    /// The command will always be valid for execution.
    /// </summary>
    /// <param name="execute">The delegate to call on execution</param>
    public DelegateCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Initializes a new instance of the DelegateCommand class.
    /// </summary>
    /// <param name="execute">The delegate to call on execution</param>
    /// <param name="canExecute">The predicate to determine if command is valid for execution</param>
    public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
        {
            throw new ArgumentNullException("execute");
        }

        this.executionAction = execute;
        this.canExecutePredicate = canExecute;
    }

    /// <summary>
    /// Raised when CanExecute is changed
    /// </summary>
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    /// <summary>
    /// Executes the delegate backing this DelegateCommand
    /// </summary>
    /// <param name="parameter">parameter to pass to predicate</param>
    /// <returns>True if command is valid for execution</returns>
    public bool CanExecute(object parameter)
    {
        return this.canExecutePredicate == null ? true : this.canExecutePredicate(parameter);
    }

    /// <summary>
    /// Executes the delegate backing this DelegateCommand
    /// </summary>
    /// <param name="parameter">parameter to pass to delegate</param>
    /// <exception cref="InvalidOperationException">Thrown if CanExecute returns false</exception>
    public void Execute(object parameter)
    {
        if (!this.CanExecute(parameter))
        {
            throw new InvalidOperationException("The command is not valid for execution, check the CanExecute method before attempting to execute.");
        }
        this.executionAction(parameter);
        }
    }
}
基本上我在屏幕上显示两个按钮和一个文本框。其中一个按钮在单击时将在文本框中显示此人的名字,另一个按钮将在同一文本框中显示此人的姓氏。如果您检查代码,您将看到我使用WPF命令实现了这一点。按钮的命令属性绑定到我的PersonViewModel类的ICommand属性。然后将这些属性“绑定”(使用DelegateCommand)到同一viewmodel类中的私有方法。我还有一个公共ShowString属性,它是绑定到屏幕上文本框的数据,用于控制文本框中显示的字符串。您将看到viewmodel类中的my private方法更改此ShowString属性的值,以更改文本框中显示的数据

我的xaml代码与您的不同(您没有提供代码),但是这个概念应该适合您


希望这有帮助。

所以,假设你正在使用笪塔斌丁的MVVM,让我们看看你的视觉树……/P> 某处你有一个按钮

<Button OnClick="MyButtonOnClick">
// Your Button Content Here
</Button>
我只演示了视图XAML的一些部分,以便您知道如何进行数据绑定-更新隐藏代码中文本框的内容不是视图的工作。这一切都应该通过适当的数据绑定来处理,不需要您更改可视树或设计

ViewModel中的person类负责向UI发出数据已更改的警报。它看起来像这样:

         <Style TargetType="{x:Type local:MyButton1}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:MyButton1}">
                        <Button>
                           <StackPanel>
                             <Label>
                              <local:MyTextBlock1 Text="Not working yet."/>
                             </Label>
                            </StackPanel>
                        </Button>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
public class Person
{
  private proeprty _firstName;
  public property FirstName
  {
    get
    {
      return _firstName;
    }
    set
    {
      _firstName = value;
      NotifyPropertyChanged("FirstName"); // This is required to notify the UI. Specific implementation will depend on your property notification pattern.
    }
  }
正确绑定的控件,如
文本框
,“侦听”以了解何时