【问题标题】:XamlWriter.Save loses ItemsSource binding from a ListBoxXamlWriter.Save 丢失 ListBox 中的 ItemsSource 绑定
【发布时间】:2012-02-18 18:34:16
【问题描述】:

我有一个自定义的 ContentControl

public class DataControl : ContentControl
{
    public List<DataItem> Options
    {
        get { return (List<DataItem>)GetValue(OptionsProperty); }
        set { SetValue(OptionsProperty, value); }
    }

    public static readonly DependencyProperty OptionsProperty =
        DependencyProperty.Register("Options", typeof(List<DataItem>), typeof(DataControl));

    public DataControl()
    {
        Options = new List<DataItem>();
    }

    public string Label
    {
        get { return (string)GetValue(LabelProperty); }
        set { SetValue(LabelProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Label.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty LabelProperty =
        DependencyProperty.Register("Label", typeof(string), typeof(DataControl));
}

public class DataItem
{
    public DataItem(string key, string value)
    {
        Key = key;
        Value = value;
    }

    public string Key { get; set; }

    public string Value { get; set; }
}

其模板被以下样式应用:

<Style TargetType="{x:Type local:DataControl}" x:Key="DefaultStyle">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:DataControl}">
                <StackPanel>
                <ListBox ItemsSource="{TemplateBinding Options}" >
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                        <Label Content="{Binding Key}" />
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
                <Label Content="{TemplateBinding Label}" />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

如果我使用 XamlWriter 保存此样式,然后再次读回,ItemsSource 绑定将丢失,但 Label 上的 Content 绑定不会。

Style style = Application.Current.TryFindResource("DefaultStyle") as Style;

string s = XamlWriter.Save(style);
Style secondStyle = XamlReader.Parse(s) as Style;

有没有办法确保 ItemsSource 绑定被正确序列化或轻松添加回来?

当尝试从另一个项目的 ResourceDictionary 获取样式时也会发生这种情况,例如

ResourceDictionary styles = new ResourceDictionary();
styles.Source = new Uri(String.Format("pack://application:,,,/StyleCopyTest;component/Styles/{0}Styles.xaml", type));
return styles;

【问题讨论】:

  • 我有,但不能解决问题。 .Net 4.0 解决方案不保留 ItemsSource 绑定,更糟糕的是会丢失 ListBox.ItemTemplate 中标签上的内容绑定。创建 ExpressionConverter 修复了 Content 绑定,但仍不保存 ItemsSource 绑定。

标签: c# .net wpf


【解决方案1】:

在 WPF 源代码中,ItemsSource 被定义为

[Bindable(true), CustomCategory("Content"),     DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IEnumerable ItemsSource { get; set; }

所以这不能被 XamlWriter 序列化。

因此您将不得不编写自己的序列化程序或使用提到的方法here

【讨论】:

    【解决方案2】:

    我找到了这个类here in code project,它可以帮助您序列化 ItemsControl 属性绑定:

    using System;
    using System.Linq;
    using System.ComponentModel;
    
    namespace GUIKonfigurator
    {
        using System.Windows.Controls;
    
        public class ItemsControlTypeDescriptionProvider:TypeDescriptionProvider
        {
            private static readonly TypeDescriptionProvider defaultTypeProvider = TypeDescriptor.GetProvider(typeof(ItemsControl));
    
            public ItemsControlTypeDescriptionProvider(): base(defaultTypeProvider)
            {
            }
    
            public static void Register()
            {
                TypeDescriptor.AddProvider(new ItemsControlTypeDescriptionProvider(), typeof(ItemsControl));
            }
    
            public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType,object instance)
            {
                ICustomTypeDescriptor defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
                return instance == null ? defaultDescriptor: new ItemsControlCustomTypeDescriptor(defaultDescriptor);
            }
        }
    
        internal class ItemsControlCustomTypeDescriptor: CustomTypeDescriptor
        {
            public ItemsControlCustomTypeDescriptor(ICustomTypeDescriptor parent): base(parent)
            {
            }
    
            public override PropertyDescriptorCollection GetProperties()
            {
                PropertyDescriptorCollection pdc = new PropertyDescriptorCollection(base.GetProperties().Cast<PropertyDescriptor>().ToArray());
                return ConvertPropertys(pdc);
            }
    
            public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
            {
                PropertyDescriptorCollection pdc = new PropertyDescriptorCollection(base.GetProperties(attributes).Cast<PropertyDescriptor>().ToArray());
                return ConvertPropertys(pdc);
            }
    
            private PropertyDescriptorCollection ConvertPropertys(PropertyDescriptorCollection pdc)
            {
                PropertyDescriptor pd = pdc.Find("ItemsSource", false);
                if (pd != null)
                {
                    PropertyDescriptor pdNew = TypeDescriptor.CreateProperty(typeof(ItemsControl), pd, new Attribute[]
                                                                                                           {
                                                                                                               new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible),
                                                                                                               new DefaultValueAttribute("")
                                                                                                           });
                    pdc.Add(pdNew);
                    pdc.Remove(pd);
                }
                return pdc;
            }
        }
    }
    

    注册完BindingConvertor后你只需要这样注册即可:

    EditorHelper.Register<BindingExpression, BindingConvertor>();
    ItemsControlTypeDescriptionProvider.Register();
    

    我做了一个快速测试,创建了一个 ComboBox 并对其进行序列化:

    ComboBox cb = new ComboBox();
    cb.Width = 100;
    cb.Height = 20;
    Binding b = new Binding("Model.Activity");
    b.Source = this.DataContext;
    cb.SetBinding(ComboBox.ItemsSourceProperty, b);
    string xaml = _Serializer.SerializeControlToXaml(cb);
    

    这里生成的 Xaml 包括 ItemsSource 绑定:

    <ComboBox Width="100" Height="20" ItemsSource="{Binding Path=Model.Activity}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />
    

    希望这会有所帮助,我仍然需要一些时间来理解它,但到目前为止似乎工作......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多