【问题标题】:WPF Update Control In Place Using XAMLReader使用 XAMLReader 就地更新 WPF 控件
【发布时间】:2011-08-26 23:27:17
【问题描述】:

我有一个现有项目,它是画布的子项。项目的样式包含在资源字典中,其中包含可用于为项目着色的各种画笔。

当创建项目的实例时,它会被赋予默认颜色。我目前无法直接与 Fill 属性进行交互,如下所示:

item.Fill = BrushBlue;

出于这个原因,我开始查看每个项目实例的 XAML。

创建实例后我对该项感兴趣的 XAML 是:

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

理想情况下,我希望能够将 Shape.Fill 值绑定到项目实例的属性,或者至少能够根据用户在应用程序中的选择更改该值。

我正在编辑项目的 XAML 以更改其填充颜色。为此,我使用以下代码,基于 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));

我正在获取 XAML,更新画笔资源名称,然后生成一个新项目。

这种方法是概念验证。我希望能够更新现有项目的 XAML,而不必在画布上创建新项目。

完成项目填充属性的“就地”更新的最佳方法是什么?

【问题讨论】:

    标签: c# wpf xaml xamlreader


    【解决方案1】:

    我假设画笔在不止一个地方被使用,这就是为什么你不能只设置 Fill 属性:

    item.Fill = Brushes.Blue;
    

    在这种情况下,您应该将项目封装到 UserControl 或自定义控件中,并使用 Brush 类型的依赖属性。 (根据画笔的用途,您也可以调用此 Fill,或者它可能更具体,例如 AccentFill、OuterBorderFill 等。)然后在您的 XAML 中,将所有这些多次出现的画笔绑定到该属性。现在您确实有了一个可以设置属性的地方,并且通过绑定它将传播到所有需要它的地方:

    item.AccentFill = Brushes.Blue;
    

    无论如何,关键是不要考虑“更新现有项目的 XAML”。 XAML 是一种序列化格式。您现有的项目已经是内存中的 .NET 对象,您可以直接在其上设置属性,而不需要从序列化表单重新加载。

    【讨论】:

    • 刷子目前只在一个地方使用,但是我目前无法直接访问该属性。我添加了有关项目样式当前设置的更多信息。
    • 从我所见,绑定方法应该适用于您的代码。在 Item 类上声明一个 Fill 依赖属性,并将您的设置器更改为 。 (注意 RelativeSource 使 Path 样式在封闭的 Item 上查找 Fill 属性。)然后您可以在代码中设置 item.Fill,绑定将检测到更改。
    • 当我将设置器更改为上述值时,它会引发以下错误:“'AncestorType {x:Type d:Item}' 字符串无法转换为'System.Windows.Data 类型的对象。 RelativeSourceMode'。AncestorType {x:Type d:Item} 不是 RelativeSourceMode 的有效值。”有什么建议吗?
    • 过失。在 AncestorType 和 {x:Type} 标记之间应该有另一个 = 符号。因此:RelativeSource={RelativeSource AncestorType={x:Type d:Item}}。对此感到抱歉。
    【解决方案2】:

    除非我误解了你的问题,否则你是真的在努力地做到这一点。为什么这不起作用?

    this.Fill = Brushes.Blue;
    

    或者如果使用资源名称很重要:

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

    也许您需要澄清您的问题以解释为什么您不能只设置值并完成它。

    【讨论】:

    • 我同意处理 XAML 是一个困难的提议。我添加了关于项目样式的说明,我认为这是阻止我直接与属性交互的原因。
    • 您可以命名它并使用 FindName(),但对于您的情况,我建议使用绑定。有关详细信息,请参阅 itowlson 的答案。
    猜你喜欢
    • 2011-03-24
    • 2010-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-07
    • 1970-01-01
    • 1970-01-01
    • 2011-07-09
    相关资源
    最近更新 更多