views:

61

answers:

2

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 ".")

+1  A: 

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
}
JSprang
Thanks for your response. (Sorry for the delay. I just got back from a short, but much needed, vacation. :-)) I'll try out this approach along with GreenIcicle's suggestion below. It's not a requirement to do this in a value converter. I am, however, trying to do this in conjunction with RIA Services. Are there any caveats that I should be aware of when using an MVVM approach as you describe above together with RIA Services?
MylesRip
I tried this out and it worked for me. FWIW... In RIA Services I can use the .shared code to add the "Value2FontWeight" property (as defined above) to my DTO (in which case I suppose it's no longer a DTO in the strictest sense, but that's okay).
MylesRip
FWIW... It seems there is a slight problem in using this approach with RIA Services (if you aren't using a view model, that is). The code that is generated for the client supplies its own setter methods for properties so the call to OnPropertyChanged("Value2FontWeight") in the solution above is never executed because it doesn't exist in the generated setter.
MylesRip
A: 

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).

GreenIcicle
Thanks for the input. JSprang's approach solved the problem and I like your suggestion to keep the interface clean by separating the evaluation of the condition from how it is indicated in the UI.
MylesRip