none
Динамическое создание интерфейса на WPF RRS feed

  • Вопрос

  • Добрый день. У меня в программе есть несколько типов редактируемых объектов, количество заранее неизвестно.

    Объекты я храню в TreeView, при выборе конкретного элемента делается видимой соответствующая вкладка (-и) в TabControl.

    При создании объекта, в коде конструктора генерируется пользовательский интерфейс и привязывается к этому объекту.

    #region Вид разрешенного использования (док.)
    label = new Label() { Content = "Вид разрешенного использования (док.)"};
    textBox = new TextBox() { Style = ValidationStyles.TextBoxStyle };
    textBox.SetBinding(TextBox.TextProperty, UIHelper.CreateBinding(this, "UtilizationByDoc"));
    groupboxGrid.Children.Add(label);
    groupboxGrid.Children.Add(textBox);
    Grid.SetColumn(textBox, 1);
    Grid.SetRow(textBox, 2);
    Grid.SetRow(label, 2);
    #endregion

    Но так получается запутанный, плохо редактируемый, и скорее всего неправильный код.

    Как  сделать, чтобы все было красиво и просто? Например создать XAML файл для каждого вида объекта, который привязывается к объекту и который потом как-то можно вставить в вкладку в TabControl?

    17 апреля 2013 г. 13:06

Ответы

Все ответы

  • Создайте для каждой вкладки UserControl. Его наполните элементами, задайте поведение, а потом в том месте где вы раньше генерировали интерфейс просто выставляйте в в таб нужный UserControl.

    Женат на WPF. Тайно встречаюсь с WinRT. Не сложилось с C#!

    17 апреля 2013 г. 15:12
    Отвечающий
  • Для каждого типа данных определите DataTemplate. В правой части пропишите <ContentPresenter Content="{Binding MyTreeView.SelectedItem}" /> и все будет работать как нужно.
    17 апреля 2013 г. 15:19
    Отвечающий
  • В ресурсах формы обьявляете несколько

    <DataTemplate DataType="DataObject">
                <Grid>
    <!--Представление вашего обьекта-->
    </Grid>
            </DataTemplate>
    после этого когда у вас выделен элемент то он будет использовать представление которое определенно в DataTemplate

    18 апреля 2013 г. 5:21
  • В ресурсах формы обьявляете несколько

    <DataTemplate DataType="DataObject">
                <Grid>
    <!--Представление вашего обьекта-->
    </Grid>
            </DataTemplate>
    после этого когда у вас выделен элемент то он будет использовать представление которое определенно в DataTemplate

    А если элемент не выделен? Начал делать так, но вроде бы вылетала ошибка.

    Сейчас ContentPresenter'у добавил тип унаследованный от ContentTemplateSelector, который выбирает из ресурсов формы нужный DataTemplate, а если значение отсутствует, возвращает MyDefaultDataTemplate

    19 апреля 2013 г. 4:43
  • Вообще должен ничего не использовать

    Покажи вашу разметку

    19 апреля 2013 г. 5:32
  • <Window.Resources>
            <DataTemplate x:Key="mezPlanTemplate" DataType="models:MezPlan">
                <localui:MezplanUserControl/>
            </DataTemplate>
            <DataTemplate x:Key="allOthersTemplate">
                <TextBlock Text="ПУСТО"/>
            </DataTemplate>
        </Window.Resources>
    
    
    <ContentPresenter Grid.Row="1" Grid.Column="1" x:Name="contentPresenter" Content="{Binding ElementName=TreeView, Path=SelectedItem.Tag}" />

    Как я делал в прошлый раз не получилось вспомнить, но при такой разметке он показывает текст, похожий на ToString() моего класса, представленного в виде object, наверно из-за того, что он привязан к элементу Tag TreeViewItem.

    Наверно надо искать примеры как привязывать объекты к самому TreeView, а не к элементам Tag его содержимого? Или Можно сделать так, чтобы ContentPresenter понимал, какого типа на самом деле передаваемый ему параметр (object) tvItem.Tag ?


    19 апреля 2013 г. 5:51
  • Вы в переменной Tag храните тип вашей записи? Если у вас коллекция состоит из разных обьектов но пронаследованных от одного, то можно привязываться напрямую без свойства Tag

    19 апреля 2013 г. 6:05
  • Когда я определял весь UI в Code-Behind, при создании Объекта (межевой план, образуемый/изменяемый участок, контур, часть) я хранил в объекте поля

    TreeViewItem

    TabPage TabCommon, TabName и т.п.

    В конструкторе объекта я создавал контролы, и при создании ставил control.Tag = this;


    19 апреля 2013 г. 6:16
  • Попробуйте тогда сделать так

    public class BaseClass {}
    public class Type1:BaseClass {}
    public class type1:BaseClass {}
    В DataContext что то в таком духе
    public List<BaseClass> items{get;set;}
    items.Add(new type1());
    items.Add(new type2());
    items.Add(new type1());
    items.Add(new type2());

    тогда в XAML разметке будет работать DataTemplate при выборе элемента

    19 апреля 2013 г. 6:29
  • Наследовать от базового класса не обязательно. Можно просто List<Object>. DataTemplate при этом тоже будет работать.
    19 апреля 2013 г. 6:49
  • <Window.Resources>
            <DataTemplate x:Key="mezPlanTemplate" DataType="models:MezPlan">
                <localui:MezplanUserControl/>
            </DataTemplate>
    </Window.Resources>
    
    <TreeView Grid.Column="0" Grid.Row="1" x:Name="TreeView" PreviewMouseRightButtonDown="TreeView_PreviewMouseRightButtonDown" >
    	<TreeView.ItemTemplate>
    		<HierarchicalDataTemplate DataType="localui:ITreeViewObject" ItemsSource="{Binding Path=Children}" >
    			<Grid Margin="7,0,10,0">
    				<TextBlock Text="{Binding Path=Header,UpdateSourceTrigger=PropertyChanged}" ContextMenu="{Binding Path=ContextMenu}"/>
    			</Grid>
    		</HierarchicalDataTemplate>
    	</TreeView.ItemTemplate>
    </TreeView>
    
    <ContentPresenter Grid.Row="1" Grid.Column="1" x:Name="contentPresenter" Content="{Binding ElementName=TreeView, Path=SelectedItem}"/>

    Вот моя разметка. Я определил интерфейс ITreeViewObject:

    public interface ITreeViewObject
    {
    	string Header { get;}
    	ObservableCollection<ITreeViewObject> Children { get; }
    	ContextMenu ContextMenu { get; }
    }

    При выборе какого-либо элемента в TreeView, в ContentPresenter выводится название класса, в чем-то похожем на TextBlock

    Например, при выборе корневого элемента


    22 апреля 2013 г. 6:33
  • Попробуйте убрать ключ:

    <Window.Resources>
            <DataTemplate DataType="models:MezPlan">
                <localui:MezplanUserControl/>
            </DataTemplate>
    </Window.Resources>
    

    22 апреля 2013 г. 6:39
  • Попробовал, ничего не изменилось.
    22 апреля 2013 г. 7:08
  • А если вместо ContentPresenter использовать ContentControl?
    22 апреля 2013 г. 7:57
  • Попробуйте

    <Window.Resources>
            <DataTemplate DataType="{x:Type models:MezPlan}">
                <localui:MezplanUserControl/>
            </DataTemplate>
    </Window.Resources>

    22 апреля 2013 г. 8:42
  • Заработало, когда заменил тип на x:Type и убрал x:Key, спасибо
    22 апреля 2013 г. 9:03