5
votes

I want to compare two versions of various properties and bold one of them if it is not equal to the other. Since SL4 doesn't support MultiBinding I am binding the FontWeight to "." so that the entire data context is passed to the converter. I then use the converter parameter to specify which fields to compare within the converter. So far, so good... Values that don't match are bolded.

The problem is that the bolded property is bound to a text box which can be edited. When the value is edited, I want the converter to be "re-activated" so that the font weight is set according to the new value. This doesn't happen. How can this be accomplished?

Note: I have already implemented INotifyPropertyChanged for the relevant class and properties. Tabbing to the next field after changing the value causes the PropertyChanged event to fire, but the font weight is not updated until I actually move to a different record and then return to the record that was changed.

(I also tried using Mode=TwoWay to see if that would do the trick. However, TwoWay binding cannot be used when you are binding to ".")

2

2 Answers

2
votes

Do you NEED to use a Value Converter? I tried this quick using the MVVM pattern and it worked pretty well. If you could use MVVM, you could possibly do it like this:

MainPage.xaml

<UserControl x:Class="BindBoldText.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BindBoldText"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">

<UserControl.DataContext>
    <local:MainPage_ViewModel/>
</UserControl.DataContext>

<StackPanel>
    <TextBlock Text="{Binding Value1, Mode=TwoWay}"/>
    <TextBlock Text="{Binding Value2, Mode=TwoWay}" FontWeight="{Binding Value2FontWeight}"/>
    <TextBox Text="{Binding Value2, Mode=TwoWay}" TextChanged="TextBox_TextChanged"/>
</StackPanel>

MainPage.xaml.cs

    public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        this.viewModel = this.DataContext as MainPage_ViewModel;
    }

    private MainPage_ViewModel viewModel;

    private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {            
        viewModel.Value2 = (sender as TextBox).Text;
    }
}

MainPage_ViewModel.cs

public class MainPage_ViewModel : INotifyPropertyChanged
{
    public string Value1
    {
        get { return value1; }
        set
        {
            if (value1 != value)
            {
                value1 = value;
                OnPropertyChanged("Value1");
            }
        }
    }
    private string value1 = "Test";

    public string Value2
    {
        get { return value2; }
        set
        {
            if (value2 != value)
            {
                value2 = value;
                OnPropertyChanged("Value2");
                OnPropertyChanged("Value2FontWeight");
            }
        }
    }
    private string value2 = "Test";

    public FontWeight Value2FontWeight
    {
        get
        {
            if (value2.Equals(value1))
            {
                return FontWeights.Normal;
            }
            else
            {
                return FontWeights.Bold;
            }
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

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

    #endregion
}
0
votes

In your solution, the value does not get updated because the property itself is bound against the whole data context via the "." expression. INotifyPropertyChanged may be called, but this event means that a single property has changed, and since you don't provide a property name in the binding expression, the data binding system does not know that the Binding needs to be updated - it can't look into what your value converter does.

I think JSprang's appraoch is a lot better, not at least because it provides better separation of presentation logic that can be tested from the markup. To go further with a clean interface, you could let the ViewModel implement a boolean property "ValuesAreSame", data-bind against it, and use a value converter to apply the actual visual style (in this case, a font weight).