WPF Update Control In Place Using XAMLReader

773 views Asked by At

I have an existing item which is a child of a canvas. The item's style is contained in a resource dictionary that contains the various brushes that can be used to color the item.

When an instance of the item is created it is given the default coloring. I am currently not able to directly interact with the Fill property as in:

item.Fill = BrushBlue;

For this reason I began looking at the XAML for each instance of the item.

The XAML I am interested in for the item after an instance is created is:

<d:Item IsSelected="True" Width="78" Height="65" Panel.ZIndex="0" Canvas.Left="233"     Canvas.Top="352.54">
    <Path ToolTip="Process">
        <Path.Style>
             <Style TargetType="Path">
                 <Style.BasedOn>
                     <Style TargetType="Path">
                         <Style.Resources>
                            <ResourceDictionary />
                         </Style.Resources>
                         <Setter Property="Shape.Fill">
                             <Setter.Value>
                                 <DynamicResource ResourceKey="ItemBrush" />
                             </Setter.Value>
                         </Setter>
                     </Style>
                 </Style.BasedOn>
             </Style>
        </Path.Style>
    </Path>
.
.
.
</d:Item>

I would ideally like to be able to tie the Shape.Fill value to a property of the instance of the item, or at least be able to change that value based on user selection in the application.

I am editing the XAML of the item to change its fill color. To accomplish this I am using the following code, based on the button clone sample from MSDN:

string savedItem = XamlWriter.Save(this) as String;

string newItem = savedItem.Replace(GetFillBrush(this), "BrushBlue");
SetFillBrush(this, "BrushBlue");

StringReader stringReader = new StringReader(newItem);
XmlReader xmlReader = XmlReader.Create(stringReader);

thisCanvas.Children.Add((Item)XamlReader.Load(xmlReader));

I am getting the XAML, updating the brush resource name and then generating a new item.

This approach was a proof of concept. I want to be able to update the XAML of the existing item without having to create a new item on the canvas.

What is the best way to accomplish this "in-place" update of the item's fill property?

2

There are 2 answers

4
itowlson On BEST ANSWER

I assume that the brush is being used in more than one place, which is why you can't just set the Fill property:

item.Fill = Brushes.Blue;

In that case what you should do is encapsulate the item into a UserControl or custom control, with a dependency property of type Brush. (Depending on the use of the brush, you might also call this Fill, or it might be more specific, e.g. AccentFill, OuterBorderFill, etc.) Then in your XAML, bind all those multiple occurrences of the brush to that property. Now you do have a single place where you can set the property, and through the bindings it will propagate to all the places it is needed:

item.AccentFill = Brushes.Blue;

In any event, the key thing is not to think about "updating the XAML of the existing item." XAML is a serialisation format. Your existing item is already a .NET object in memory and you can set properties on it directly rather than needing to reload from a serialised form.

2
Ray Burns On

Unless I am misunderstanding your question, you are really doing it the hard way. Why wouldn't this work?

this.Fill = Brushes.Blue;

or if it is important to use a resource name:

this.Fill = (Brush)FindResource("BlueBrush")

Maybe you need to clarify your question to explain why you can't just set the value and be done with it.