سؤال

أواجه بعض المتاعب الخطيرة خلق WPF TreeView مع كائن ربط البيانات.

التطبيق هو config محرر.قمت بتعريف كائن الهيكل الذي يمكن أن يكون تسلسل الصحيح تنسيق XML.

المشكلة أواجه هو التنسيق مثيل الكائن في TreeView تبين الصحيح الهرمي.TreeView إلا جعل قناة عقدة و لا شيء آخر.

public class Objects
{
    public List<Channel> Channels { get; set; }
}

public class Channel 
{
    public string Id { get; set; }
    public string Name { get; set; }
    public Reader Reader { get; set; }
    public Filters Filters { get; set; }
    public Router Router { get; set; }
    public Persister Persister { get; set; }
}

public class Filters : ArrayList
{
    public string StopOnFailure { get; set; }
}

public class Reader
{
    public string Id { get; set; }
    public string Name { get; set; }
}

جميع الطبقات الطفل من Channel تحتوي على خصائص Id و Name.مرشحات الصف هو مجموعة من الأنواع الأخرى مع نفس الخاصية التعريف.

هنا هو XAML

 <Window.Resources>
    <ObjectDataProvider x:Key="data"/>
    <DataTemplate DataType="{x:Type ConfigurationEditor:Channel}">
        <WrapPanel>
            <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" />
            <TextBlock Text=" [" />
            <TextBlock  Text="{Binding Path=Id}" />
            <TextBlock Text="]" />
        </WrapPanel>
    </DataTemplate>
    <DataTemplate DataType="{x:Type ConfigurationEditor:Reader}">
        <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>
</Window.Resources>
<Grid>
    <TreeView Margin="12,12,12,96" Name="treeView1" ItemsSource="{Binding Source={StaticResource data}, Path=Channels}">
    </TreeView>
</Grid>

رمز وراء إنشاء البيانات سبيل المثال

Objects config;
var serializer = new XmlSerializer(typeof(Objects));
using (var stream = new FileStream(@"C:\test.xml", FileMode.Open))
{
    config = (Objects)serializer.Deserialize(stream);
}

var dp = (ObjectDataProvider)FindResource("data");
dp.ObjectInstance = config;

لقد ألقيت نظرة على أمثلة لا حصر لها ولكن ما زلت لا يمكن معرفة ما أفعله خطأ.شكرا للمساعدة.

تحديث:

<HierarchicalDataTemplate DataType="{x:Type ConfigurationEditor:Objects}" ItemsSource="{Binding Path=Channels}"/>
<HierarchicalDataTemplate DataType="{x:Type ConfigurationEditor:Channel}" ItemsSource="Binding Path=Reader}">
    <TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>

<DataTemplate DataType="{x:Type ConfigurationEditor:Reader}">
    <TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>

لا تغيير TreeView.مع هذا التغيير لا يزال لدي فقط Channel سرد و لا شيء آخر.

هل كانت مفيدة؟

المحلول

التوسع في @Gimalay الجواب, المشكلة هي أن TreeView لا أعرف أين يمكن الحصول على البيانات لأي طفل العقد.يمكنك إبلاغ TreeView باستخدام HierarchialDataTemplate, بدلا من DataTemplate:

<HierarchialDataTemplate DataType="{x:Type ConfigurationEditor:Channel}"
    ItemsSource="...">
    <WrapPanel>
        <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" />
        <TextBlock Text=" [" />
        <TextBlock  Text="{Binding Path=Id}" />
        <TextBlock Text="]" />
    </WrapPanel>
</HierarchialDataTemplate>

والفرق الرئيسي بين الاثنين هو ItemsSource السمة.هذا هو ملزم التعبير بإرجاع مجموعة من الكائنات لاستخدام الطفل العقد.

المشكلة هي أن لديك عدد قليل من الخصائص للحصول على الأطفال ، وليس واحدة فقط.تحتاج إما إلى الجمع بين كل منهم في خاصية واحدة ، أو إضافة عقار آخر يعود كل من الطفل العقد.

أخيرا, سوف تحتاج إلى تعريف DataTemplate لكل طفل نوع البند ، بحيث TreeView يعرف كيفية عرض لهم (يمكنك استخدام HierarchialDataTemplate الأطفال كما لو كانوا في تحويل الطفل العقد).

نصائح أخرى

أنا لا أعتقد أنك بحاجة إلى هذا النموذج الأشياء لا تأتي أبدا في الصورة في TreeView.

<HierarchicalDataTemplate
    DataType="{x:Type ConfigurationEditor:Objects}" 
    ItemsSource="{Binding Path=Channels}"/>

كنت قد وضعت هذا في XAML ، مما يدل على القنوات..الكمال!

<TreeView 
    Margin="12,12,12,96" Name="treeView1" 
    ItemsSource="{Binding Source={StaticResource data}, Path=Channels}">
</TreeView>

الآن تريد للقارئ أن يظهر كذلك. ولكن واحدة فقط يمكن تحديد كائنات من نوع IEnumerable كما ItemsSource, لذا القالب أدناه هو غير الصحيحة التي تنص على "القارئ" كما ItemsSource.

<HierarchicalDataTemplate 
    DataType="{x:Type ConfigurationEditor:Channel}" 
    ItemsSource="{Binding Path=Reader}">
    <TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>

حتى إذا كنت تريد اسم القارئ إلى أن تظهر وكذلك استخدام القالب كما هو موضح أدناه.

<DataTemplate 
    DataType="{x:Type ConfigurationEditor:Channel}" >
    <StackPanel>
        <TextBlock Text="{Binding Path=Name}"/>
        <TextBlock Text="{Binding Path=Reader.Name}"/>
    <StackPanel>
</DataTemplate>

من أجل ذلك البيانات الهرمية قوالب تستخدم عندما البنود مصدر في الواقع التسلسل الهرمي داخل نفسه.أي أن الكائنات نفسها بعض الهرمي مع الكائنات الأصل حفظ قائمة من الكائنات التابعة.

وعلى سبيل المثال ، قد يكون كل قناة لديها خاصية SubChannels مثل أدناه.

public class Channel 
{
    public string Id { get; set; }
    public string Name { get; set; }
    public ObservableCollection<Channel> SubChannels { get; }
}

ثم نحن يمكن أن تستخدم قالب مثل هذا.

<HierarchicalDataTemplate 
    DataType="{x:Type ConfigurationEditor:Channel}" 
    ItemsSource="{Binding Path=SubChannels}">
    <TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>

الآن بنية الكائن يمكن أن يكون متعدد المستويات العميقة مع كل subchannel مرة أخرى بعد أن subchannels.

أيضا لاحظ أنه في المثال استخدمت نفس النوع, قناة, على إنشاء التسلسل الهرمي من subchannels.ونحن يمكن أن تستخدم نوع آخر ، ويقول كل قناة وجود قائمة من القراء.

حسنا, بعد الكثير من المحاكمة خطأ كنت قادرا على الحصول على هذا العمل كما أردت.هنا هو كيف فعلت ذلك.

في بلدي Channel كائن لقد تم إضافة خاصية جديدة أن مجموعة من الخصائص الأخرى التي أردت عرضها في TreeView

public ArrayList Components
{
    get { return new ArrayList { Reader, Filters, Router, Persister  }; } 
    set
    {
        ArrayList list = value;
        if (list != null)
        {
            foreach (var item in list)
            {
                if (item is Reader)
                {
                    Reader = (Reader)item;
                }
                else if (item is Router)
                {
                    Router = (Router) item;
                }
                else if (item is Persister)
                {
                    Persister = (Persister) item;
                }
                else if (item is Filters)
                {
                    Filters = (Filters) item;
                }
            }
        }
    }
}

ثم XAML على النحو التالي لعرض treeview.

    <HierarchicalDataTemplate DataType="{x:Type ConfigurationEditor:Channel}" ItemsSource="{Binding Path=Components}">
        <WrapPanel>
            <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" />
            <TextBlock Text=" [" />
            <TextBlock  Text="{Binding Path=Id}" />
            <TextBlock Text="]" />
        </WrapPanel>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate DataType="{x:Type ConfigurationEditor:Filters}" ItemsSource="{Binding Path=.}">
        <TextBlock Text="Filters"/>
        <HierarchicalDataTemplate.ItemTemplate>
            <DataTemplate >
                <TextBlock Text="{Binding Path=Name}"/>
            </DataTemplate>
        </HierarchicalDataTemplate.ItemTemplate>
    </HierarchicalDataTemplate>
    <DataTemplate DataType="{x:Type ConfigurationEditor:Reader}">
        <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type ConfigurationEditor:Router}">
        <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type ConfigurationEditor:Persister}">
        <TextBlock Text="{Binding Path=Name}"/>
    </DataTemplate>

شكرا اندي تضعني على الطريق الصحيح.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top