Alan Wayne
Alan Wayne

Reputation: 5384

Changing Textblock background in WPF resetting itself after color change

I have a textblock in a WPF usercontrol defined as:

<TextBlock Grid.Column="0"
           Text="{Binding RecognitionResults}"
           Background="{Binding ResultBackground}" />

The UserControl in which the TextBlock is displayed is being presented as a String from another UserControl as:

<ItemsControl ItemsSource="{Binding Strings}" >
      <ItemsControl.ItemContainerStyle>
           <Style>
                <Setter Property="Control.Margin"
                        Value="{Binding Margin}"/>
           </Style>
      </ItemsControl.ItemContainerStyle>
 </ItemsControl>  

Essentially, the ItemsControl is presenting a list of "Strings", each string itself being represented by its own UserControl.

Now, when I Tap on the display of the TextBlock, the gesture performs this action to change the background color from yellow to green in the ViewModel:

public void Refill()
{
    ResultBackground = Brushes.Green;
}

The ResultBackground color is defined in the ViewModel as:

 private SolidColorBrush resultbackground =
     (SolidColorBrush)new BrushConverter().ConvertFromString("#FFEFF100");

 public SolidColorBrush ResultBackground
 {
      get
      {
           Console.WriteLine("Now getting resultbackground of "
               + resultbackground);
           return resultbackground;
      }
      set
      {
          if (resultbackground != value)
          {
              resultbackground = value;
              OnPropertyChanged("ResultBackground");
          }
      }
 }

So, when I physically tap on the TextBlock, the gesture will successfully turn it from yellow to green. So far so good.

However, when I execute the Refill() method from a command (i.e., a menu command), the TextBlock first turns the green (like it should) but then redisplays as the initial yellow. Watching the output from the Console.WriteLine above confirms that the get is first called to turn the box green from Refill(), but then (there is no stack trace), the get is called again (without the set being called) that retrieves yellow!

I am at a complete loss as to why this is happening or what to do to fix it. The only places in code where ResultBackground is even referenced is in the above code.

Any help in getting this to work would be most appreciated.

Edit: I don't know if it is relevant or not, but the command that executes refill() is being executed as an Action from the menu as:

 <UserControl x:Class="Nova5.UI.Views.Ink.InkView"
        ............................

<UserControl.Resources>
    <Style x:Key="MenuItemStyle" TargetType="{x:Type MenuItem}">
         <Setter Property="Command" Value="{Binding OnSelected}" />
    </Style>
</UserControl.Resources>


<Grid>
    <Grid.Resources>
        <HierarchicalDataTemplate DataType="{x:Type m:MyMenuItem}" ItemsSource="{Binding Path=SubItems}">
            <ContentPresenter
                Content="{Binding Path=DisplayText}"
                RecognizesAccessKey="True" />
        </HierarchicalDataTemplate>
    </Grid.Resources>

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="25" />
    </Grid.RowDefinitions>

    <Menu Grid.Row="3" Height="28" >
        <MenuItem Header="Options" ItemsSource="{Binding OptionSubItems}" DisplayMemberPath="{Binding DisplayText}" >
            <MenuItem.ItemContainerStyle>
                <Style>
                    <Setter Property="MenuItem.Command"  Value="{Binding OnSelected}"/>
                </Style>
            </MenuItem.ItemContainerStyle>
        </MenuItem>
    </Menu>

</Grid>

Where OptionSubItems is built in the viewmodel constructor as:

  OptionSubItems = new ObservableCollection<MyMenuItem>();

and MyMenuItem is:

   public class MyMenuItem : MenuItemBase
{
    private Action Command;

    public MyMenuItem(String DisplayText, Action command)
    {
        this.DisplayText = DisplayText;

        this.Command = command;
    }
    public override void OnItemSelected()
    {
        this.Command();
    }
}

The ViewModel constructor dynamically builds the command list as:

    OptionSubItems.Add(new MyMenuItem("Refill", delegate()
        {
            CurrentViewModelDetails.ExecuteMenuCommand("Refill");
        }));

and ExecuteMenuCommand does:

     if (commandname == "RefillAllCurrentPrescriptions")
        {

            for (int k = 0; k < Strings.Count; k++)
            {
                Strings[k].refill();
            }
        }

Hope this helps. (I wondering if the problem is in the above xaml with two bindings to the OnSelected from different styles?)

Upvotes: 0

Views: 446

Answers (1)

Alan Wayne
Alan Wayne

Reputation: 5384

O.K., at risk of total embarrassment, here is the original code that was causing the blinking problem:

 OptionSubItems.Add(new MyMenuItem("Refill all current prescriptions", delegate()
        {
            CurrentViewModelDetails.ExecuteMenuCommand("RefillAllCurrentPrescriptions");
             CurrentViewModelDetails.RefreshDisplay(RxViews.PrescriptionList);
            DialogTitle = "Current Prescriptions";
        }));

The RefreshDisplay() method was rebuilding the display from the database and totally dropping the effects of the refill()--which explains why breakpoints placed on the get{} did not show any stack trace. The get{} were being called by the XAML when the new objects were created; there was no set{} involved. So the above code actually works fine (after I removed the offending line to be more concise for SO).

To give credit where credit is due, it was Rachel's suggestion that led to restudying the delegates, but thanks to all for the help.

Upvotes: 1

Related Questions