XamlWriter теряет связь - хорошо!но как сохранить значение?(ItemsControl) - PullRequest
2 голосов
/ 12 июля 2010

я знаю, что стандартный XamlWriter не сохраняет привязки. но что действительно воняет, так это то, что текущее значение, которое содержит привязка, тоже не сериализуется.

мой текущий - действительно глупый - обходной путь - это создать DependencyProperty fooProperty и свойство foo. а также свойство foo2. Затем обработчик изменений foo записывает свое значение в foo2.

вы видите: глупо.

У кого-нибудь есть лучшее решение?

ура

- редактировать в ответ на Томаса -

в принципе ты прав. но при использовании ItemsControl это выглядит немного иначе:

<Window x:Class="TestApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestApp"
    Title="MainWindow" Height="350" Width="525"
    x:Name="window"
    >
<StackPanel>
    <StackPanel.Resources>
        <x:Array x:Key="arr1" Type="{x:Type local:TestData}">
            <local:TestData Message="itemcontrol binding 1"/>
            <local:TestData Message="itemcontrol binding 2"/>
        </x:Array>
   </StackPanel.Resources>

    <local:Test Foo="hard coded"/>
    <local:Test Foo="{Binding Message, ElementName=window}"/>
    <ItemsControl ItemsSource="{StaticResource arr1}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <local:Test Foo="{Binding Path=Message }"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Message = "direct binding";
    }

    public static DependencyProperty MessageProperty = DependencyProperty.Register("Message", typeof(string), typeof(MainWindow));
    public string Message
    {
        get { return (string)GetValue(MessageProperty); }
        set { SetValue(MessageProperty, value); }
    }
}

public class Test : TextBox
{
    public static DependencyProperty FooProperty = DependencyProperty.Register("Foo", typeof(string), typeof(Test), new PropertyMetadata(OnFooChanged));
    private static void OnFooChanged(DependencyObject d, DependencyPropertyChangedEventArgs a)
    {
        (d as Test).Text = a.NewValue as String;
    }
    public string Foo
    {
        get { return (string)GetValue(FooProperty); }
        set { SetValue(FooProperty, value); }
    }

    protected override void OnMouseEnter(MouseEventArgs e)
    {
        Debug.Print("foo is really: " + Foo);
        Debug.Print(XamlWriter.Save(this));
    }
}

public class TestData : DependencyObject
{
    public static DependencyProperty MessageProperty = DependencyProperty.Register("Message", typeof(string), typeof(TestData));
    public string Message
    {
        get { return (string)GetValue(MessageProperty); }
        set { SetValue(MessageProperty, value); }
    }
}

если вы запустите это тестовое приложение и наведете курсор на различные текстовые поля, вы увидите, что нет проблем с сериализацией жестко закодированных и непосредственно связанных значений. напротив, привязка к данным не сериализуется.

кстати, нет никакой разницы в использовании ItemSource, сгенерированного кодом вместо StaticReference, только что протестировал это.

Ответы [ 2 ]

0 голосов
/ 16 февраля 2012

Я видел то же самое в идентичном случае привязки внутри ItemTemplate:

<ListBox.ItemTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding}"/>
    </DataTemplate>
</ListBox.ItemTemplate>

Лучшее, что я мог сделать, это следующий обходной путь:

private static UIElement ClonedElement(UIElement original)
{
    var clone = (UIElement)XamlReader.Parse(XamlWriter.Save(original));

    if (original is TextBlock)
        //Handles situation where databinding doesn't clone correctly.
        ((TextBlock)clone).Text = ((TextBlock)original).Text;
    return clone;
}

Это не красиво, но работает. (И это может быть легко изменено для любого свойства, которое вы теряете.)

0 голосов
/ 13 июля 2010

Значение равно и XamlWriter.См. Эту страницу:

Ограничения сериализации XamlWriter.Save

Общие ссылки на объекты, созданные различными форматами расширения разметки, такими как StaticResource или Binding, будутразыменовывается процессом сериализации.Они уже были разыменованы в то время, когда объекты в памяти создавались средой выполнения приложения, и логика Save не восстанавливает исходный XAML для восстановления таких ссылок в сериализованный вывод. Это потенциально замораживает любое значение базы данных или полученного ресурса, чтобы оно стало последним значением, используемым представлением времени выполнения , с ограниченной или косвенной способностью отличать такое значение от любого другого значения, установленного локально.Изображения также сериализуются как ссылки на объекты к изображениям в том виде, в каком они существуют в проекте, а не как ссылки на оригинальные источники, теряя любое имя файла или URI, на которые изначально ссылались.Даже ресурсы, объявленные на одной и той же странице, отображаются сериализованными в точку, на которую они ссылаются, а не сохраняются в качестве ключа коллекции ресурсов.

Я только что провел простой тест, и он отлично работаетдля меня:

public class Test : DependencyObject
{
    public static DependencyProperty FooProperty = DependencyProperty.Register("Foo", typeof(string), typeof(Test));

    public string Foo
    {
        get { return (string)GetValue(FooProperty); }
        set { SetValue(FooProperty, value); }
    }

    public static DependencyProperty BarProperty = DependencyProperty.Register("Bar", typeof(int), typeof(Test));

    public int Bar
    {
        get { return (int)GetValue(BarProperty); }
        set { SetValue(BarProperty, value); }
    }
}

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        Message = "Hello";
        Answer = 42;

        var t = new Test();

        Binding fooBinding = new Binding("Message") { Source = App.Current };
        BindingOperations.SetBinding(t, Test.FooProperty, fooBinding);

        Binding barBinding = new Binding("Answer") { Source = App.Current };
        BindingOperations.SetBinding(t, Test.BarProperty, barBinding);

        var s = XamlWriter.Save(t);
        Debug.Print(s);

    }

    public string Message { get; set; }
    public int Answer { get; set; }
}

Эта программа печатает следующий XAML в выходных данных отладки:

<Test Foo="Hello" Bar="42" xmlns="clr-namespace:WpfApplication1;assembly=WpfApplication1" />

Так что должна быть другая причина, почему она не работает в вашем случае ... выуверены, что у вас нет ошибок привязки?Есть ли у объекта ожидаемые значения до того, как вы его сериализуете?

...