WPF Databinding vs Программно генерирующие элементы управления - PullRequest
0 голосов
/ 27 мая 2019

Моя базовая структура данных состоит из иерархии объектов, построенных на общем абстрактном классе:

public abstract class model {
   public string name {get;};
   public string type {get;};
}

public class A:model {
   public int val1 {get; set;}; 
}

public class B:model {
   public int val2 {get; set;}; 
}

public class C:B {
   public Dictionary<string, int> extra_props; 
}

Моя цель - создать пользовательский интерфейс, который после выбора объекта может динамически просматривать, но также и изменять базовые свойства объекта.

Я абсолютный новичок в отношении WPF, поэтому я не знаю, каковы его полные возможности. А пока что касается свойств с одним значением, я нашел способ использовать привязку данных для привязки свойств к элементам пользовательского интерфейса. Он работает как брелок для показа и изменения значений.

<GroupBox x:Name="InfoBox" Header="Object Information">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="41*"/>
            <ColumnDefinition Width="200*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20"/>
            <RowDefinition Height="50*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <DockPanel Grid.Row="0" Grid.ColumnSpan="2" >
            <TextBlock>Name:</TextBlock>
            <TextBlock Text="{Binding name}" HorizontalAlignment="Right"></TextBlock>
        </DockPanel>
        <DockPanel Grid.Row="1" Grid.ColumnSpan="2" >
            <TextBlock>Type:</TextBlock>
            <TextBlock Text="{Binding type}" HorizontalAlignment="Right"></TextBlock>
        </DockPanel>
        <DockPanel Grid.Row="2" Grid.ColumnSpan="2" >
            <TextBlock>Material Name:</TextBlock>
            <TextBlock Text="{Binding val1}" HorizontalAlignment="Right"></TextBlock>
        </DockPanel>
    </Grid>
</GroupBox>

Задача 1: Когда объект типа B связан, свойство val1 не существует, и я получаю некоторые BindingErrors в выходных данных отладки. Они не вызывают никаких проблем во время выполнения, но я не нашел способа перехватить их и вернуть значение по умолчанию или что-то еще.

Единственный способ, который я задумал для решения этой проблемы, - это добавить все требуемые свойства в абстрактный класс, чтобы они все существовали во всех производных классах с некоторыми нулевыми значениями или чем-то, но это не так все.

Задача 2: Для более сложных классов, таких как C, я хочу динамически генерировать пользовательский интерфейс на основе набора / списка свойств класса. На данный момент я абсолютно не знаю, как это сделать с привязкой данных, за исключением добавления их всех по одному в XML и решения проблем 1. 1. 1020 *

Самое жизнеспособное решение, о котором я подумал, - это программно сгенерировать элемент управления и добавить его в главное окно с текстовыми полями и входными данными для нужных мне свойств класса, и, опять же, программно, надеюсь, мы сможем привязать объект к элементу управления, чтобы что значения считываются / устанавливаются соответствующим образом. Очевидно, этот метод решит и проблему 1.

Я даже не уверен, возможно ли это решение или нет, но в любом случае мне нужны рекомендации и советы, главным образом, если есть способ решить мои проблемы с привязкой данных или мне следует пойти с программным обновлением пользовательский интерфейс (если возможно).

1 Ответ

1 голос
/ 27 мая 2019

Что ж, для новичка у вас все хорошо :) На самом деле существует очень простое решение обеих этих проблем: DataTemplates.Вы можете прочитать все о них на сайте Microsoft .

В вашем случае вы хотите объявить отдельный шаблон для каждого типа, который вы пытаетесь отобразить:

 <DataTemplate DataType="{x:Type local:A}">
     <TextBlock Text="This object is type A">
 </DataTemplate>

 <DataTemplate DataType="{x:Type local:B}">
     <TextBlock Text="This object is type B">
 </DataTemplate>

... и так далее.Обычно это делается в блоке ресурсов любого оконного / пользовательского элемента управления, на котором появляется этот код, хотя он также может быть объявлен в блоке ресурсов App.xaml и т. Д.

DataTemplates используются любым элементом управления WPF, который являетсявозможность привязки к данным каким-либо образом.Возьмите, например, Button ... общий вид кнопки, включая границу и то, как она ведет себя при наведении мыши и т. Д., Определяется ее ControlTemplate (который вы, конечно, также можете переопределить).Но в какой-то момент в XAML он должен отобразить фактические данные, которые вы присвоили его свойству «Content», и если бы вы взглянули на ControlTemplate for Button, вы бы обнаружили внутри него что-то вроде этого:

<ContentPresenter />

Это фактически говорит: «Хорошо, это то место, где мои фактические данные должны быть отображены, но вместо того, чтобы объявлять их здесь, я хочу, чтобы вы вместо этого ссылались на соответствующий DataTemplate объекта».Таким образом, вы можете создать стиль кнопок верхнего уровня, используя одну ControlTemplate, но затем вы можете указать несколько DataTemplates для каждого из типов объектов, которые вы будете визуализировать внутри него.

Многие элементы управления используют DataTemplateвключая такие элементы, как ListBox и т. д., где каждому элементу списка может быть присвоено различное графическое представление в зависимости от его типа.Возвращаясь к вашей конкретной проблеме: если вы просто хотите отобразить сами данные без каких-либо наворотов и т.п., просто используйте ContentControl:

 <ContentControl Content="{Binding MyModel}" />

Так что MyModel должно быть свойствомтипа model, который находится в слое модели представления (или в другом месте, для которого вы установили DataContext).Присвоение этого свойства экземпляру типа A, B или C приведет к заполнению ContentControl экземпляром того, что вы объявили в его DataTemplate.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...