MVVM动态更改属性

时间:2017-03-24 03:55:31

标签: c# wpf mvvm

当我的名字" David"时,我试图动态更改此前景值。输入:

<RichTextBox x:Name="richTextBox" Height="100" Width="366">
        <FlowDocument>
            <Paragraph>
                <Run Text="{Binding Customer.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Foreground="{Binding Customer.TColor}"/>
            </Paragraph>
        </FlowDocument>
    </RichTextBox>

我将前景绑定到TColor。我已经更改了设置的颜色以确认绑定是否正常工作 在我的模型中,我的客户类具有以下构造函数,TColor属性和OnPropertyChanged方法:

public class Customer : INotifyPropertyChanged, IDataErrorInfo
{
    private string name;
    private string tColor;
    private string defaultColor = "#000000";
    /// <summary>
    /// constructor
    /// </summary>
    public Customer(String customerName)
    {
        Name  = customerName;
        TColor = defaultColor;
    }

    public string TColor
    {
        get
        {
            return tColor;
        }
        set
        {
            tColor = defaultColor;
            OnPropertyChanged("TColor");
        }
    }
    /// <summary>
    /// getter and setter
    /// </summary>
    public String Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
            OnPropertyChanged("Name");
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion

我的视图模型CustomerViewModel类具有我的ChangeColor方法,如果调用它,则应将颜色设置为相应的值。我在这个课程中的一个问题是我后来提到的ChangeColorCommand类如何使用我的CanUpdate方法。我看到的另一个问题但是我不知道答案是,如果我可以在同一个地方使用UpdateCommand两次我初始化另一个。然而,CustomerUpdateCommand的UpdateCommand做了它应该做的事情。

internal class CustomerViewModel
{
    private Customer customer;
    private CustomerInfoViewModel childViewModel;

    /// <summary>
    /// init new instance of the class
    /// </summary>
    public CustomerViewModel()
    {
        //you could use this for a new Twitter user
        customer = new Customer("David");
        childViewModel = new CustomerInfoViewModel();
        UpdateCommand = new ChangeColorCommand(this);
        UpdateCommand = new CustomerUpdateCommand(this);
    }

    public bool CanUpdate
    {
        get
        {
            if (!(Customer.Name == "David"))
            {
                return false;
            }
            return true;
        }
    }

    /// <summary>
    /// Gets the customer instance
    /// </summary>
    public Customer Customer
    {
        get
        {
            return customer;
        }
    }

    /// <summary>
    /// gets the update command for the view model
    /// </summary>
    public ICommand UpdateCommand
    {
        get;
        private set;
    }

    public void ChangeColor()
    {
        Customer.TColor = "#0000ff"; 
    }
    /// <summary>
    /// saves changes made to the customer instance
    /// </summary>
    public void SaveChanges()
    {
        CustomerInfoView view = new CustomerInfoView()
        {
            DataContext = childViewModel
        };

        childViewModel.Info = Customer.Name + " was updated in the database.";

        view.ShowDialog();
        //Debug.Assert(false, String.Format("{0} was updated.", Customer.Name));
    }
}

我可能在我的ChangeColorCommand中找到了一个错误的地方:

internal class ChangeColorCommand : ICommand
{
    private CustomerViewModel viewModel;

    public ChangeColorCommand(CustomerViewModel viewModel)
    {
        this.viewModel = viewModel;
    }

    #region ICommand members

    public event System.EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter)
    {

        return viewModel.CanUpdate;
      //return String.Equals(this, "David")
    }

    public void Execute(object parameter)
    {
        viewModel.ChangeColor();
    }

    #endregion
}

如果我错过了有关我的代码的详细信息,可以在this repository

找到整个项目

3 个答案:

答案 0 :(得分:2)

数据触发器怎么样

<Style TargetType="RichTextBox">
      <Setter Property="Foreground"
                  Value="PutYourdefaultColor" />
      <Style.Triggers>
        <DataTrigger Binding="{Binding Customer.Name}"
                     Value="David">
          <Setter Property="Foreground"
                  Value="Green" />
        </DataTrigger>
      </Style.Triggers>
</Style>

答案 1 :(得分:2)

以下是执行此操作的方法......

<RichTextBox x:Name="richTextBox" Height="100" Width="366">
  <FlowDocument>
    <Paragraph  Foreground="{Binding Customer.Color}">
      <Run Text="{Binding Customer.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
    </Paragraph>
  </FlowDocument>
</RichTextBox>

WHERE ...

    public Brush Color
    {
        get
        {
            return name.Length > 0 && name[0] == 'D' ? Brushes.Red : Brushes.Black;
        }
    }

这是关键部分......

    /// <summary>
    /// getter and setter
    /// </summary>
    public String Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
           PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));
        }
    }

请注意以下事项:

  1. 前景色在段落上设置,而不是运行。由于某种原因,这不会起作用。
  2. 设置名称时,需要指示颜色已更改。否则颜色将不会更新。

答案 2 :(得分:0)

不完全确定程序应该做什么,但我看到了2个问题:

  • 您指定UpdateCommand两次,因此您的ChangeColor永远不会 去上班
  • TColor属性设置器中,您不使用value

此外,RichTextBox中存在绑定问题。删除或更改“大卫”后,您会拆分或完全删除Run。只需使用绑定到TextBox的另一个Name进行尝试,然后观察行为