powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / WPF: Не получается отобразить контент
19 сообщений из 19, страница 1 из 1
WPF: Не получается отобразить контент
    #39206656
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хочу немножко модифицировать кнопку, при этом чтобы она продолжала работать как ContentControl. Делаю юзерконтрол.
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
<UserControl x:Class="MyNamespace.MyButton"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Button HorizontalContentAlignment="Left">
  </Button>

</UserControl>


добавляю его по месту прописки
Код: xml
1.
2.
3.
      <local:MyButton>
        bla-bla-bla
      </local:MyButton>


Работает, контент, понятное дело не отображается, он хранится в UserControl.Content.
Пытаюсь его отобразить:
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
<UserControl x:Class="MyNamespace.MyButton"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Button HorizontalContentAlignment="Left"
          Content="{Binding Content, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}">
  </Button>

</UserControl>


либо так:
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
<UserControl x:Class="MyNamespace.MyButton"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <Button HorizontalContentAlignment="Left">
    <ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" />
  </Button>

</UserControl>


В первом случае ругается при компиляции, что мол объект не может быть родителем самого себя. Во втором случае запускается, но вываливается со Stack Overflow.

Понятно, что возникает зацикленность в визуальном дереве, но не могу понять почему. Ведь контент должен отобразиться только один раз, внутри кнопки, куда я его перенес. Откуда зацикливание?

При этом совершенно аналогичный подход с переносом контента в DataTemplate работает без проблем. Что же здесь не так и как было бы правильно сделать (хочу именно юзерконтрол)?
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39206998
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
не понял, что ты хочешь сделать
для того, чтоб поменять внеший вид кнопки, надо задать ей Template в качестве ControlTemplate с ContentPresenter'ом внутри, свойства ContentPresenter'а можно не обьявлять, так как по умолчанию для ContentSource идет Content.
Если свойство контрола с заданным представлением можно задать через ContentSource для ContentPresenter'а

Вообще в работе, UserControl'ы я не использую вообще, это дерьмо. UserControl по сути, это ContentControl, который содержит в себе ContentPresenter. Если мне надо свой контрол или переопределить кнопку, я просто создам класс базирующийся на Button или BaseButton или ContentControl, а если мне содержимое не требуется, то просто Control.
Задам ключи стиля по умолчанию, если мне это нужно.
И добавлю или изменяю поведение контрола.
Зачем UserControl в WPF я не знаю, мне не понятна в чем его +сы.
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39207031
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman MejtesЗачем UserControl в WPF я не знаюна мой взгляд для того, чтобы создать привычный шаблон для программиста. То есть создаешь объект в виде отдельного файла, набиваешь его своей логикой и внешним видом, можешь таскать файл между проектами, вставляешь одним движением в произвольное место своей формы, причем аналогично стандартным контролам.
ControlTemplate ведь просто так не воткнешь, его надо где-то положить в ресурс, подключить ресурс к проекту, потом переопределять этим ресурсом стандартный шаблон - то есть UserControl в этом плане нагляднее и удобнее просто за счет втыкания лишнего уровня абстракции.


Roman Mejtesдля того, чтоб поменять внеший вид кнопки, надо задать ей Template в качестве ControlTemplate с ContentPresenter'ом внутри, свойства ContentPresenter'а можно не обьявлять, так как по умолчанию для ContentSource идет Content.Что я делаю не так?
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
      <Button>
        <Button.Template>
          <ControlTemplate>
            <Border BorderBrush="Black" BorderThickness="1">
              <ContentPresenter />
            </Border>
          </ControlTemplate>
        </Button.Template>
        <TextBlock Text="bla-bla" />
      </Button>

Если ничего не задавать для контентпрезентера, то ничего и не отображается внутри кнопки
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39207033
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.ProЧто я делаю не так?так, на этот вопрос ответ нашел
Код: xml
1.
<ControlTemplate TargetType="Button">
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39207038
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtesне понял, что ты хочешь сделатьВ общем, возвращаясь к изначальному вопросу.

Забудем о кнопке, она была просто в качестве простого примера. Хочу создать свой юзерконтрол, который ведет себя как контент-контрол, то есть чтобы я добавлял его на форму классическим образом:
Код: xml
1.
2.
3.
      <local:MyControl>
        bla-bla-bla
      </local:MyControl>

Соответственно, где-то среди прочего барахла в визуальном дереве я размещаю ContentPresenter, который отобразит контент, "переданный сверху".
Код: xml
1.
2.
3.
4.
5.
  <StackPanel>
    <TextBlock Text="sss" />
    <ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" />
    <TextBlock Text="sss" />
  </StackPanel>

ну вот эта-то штука и приводит к зацикливанию, и я пока не могу сообразить, как правильно
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39207052
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Похоже нашел ответ и на этот вопрос. В UserControl.Content лежит не то, что я положил туда в разметке формы, а то, чем я набиваю этот самый юзерконтрол (то есть StackPanel в последнем случае). Отсюда и зацикливание - я пытаюсь отобразить родительский элемент как дочерний. Выход - использование атрибута ContentProperty, чтобы переназначить свойство контента по умолчанию.
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39207473
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
для того, чтоб не было проблем ресурсами, в проекте в котором лежит мой Control есть папка Themes с файлом Generic.xaml в котором и хранятся все ресурсы для данного контрола.
По сути Control или UserControl\ContentControl, не должны ни чего знать о ViewModel, все его состояния и значения должны определяться в DependencyProperty или Property через соответствующие значения.
А уже потом мы этот контрол применяем в шаблоне DataTemplate, для соответствующей модели, у это шаблона для связывания с соответствующей моделью это DataType. В шаблоне мы имеем полный пакет триггеров ) Легкое связывание, за счет IntelliSense, ведь тип нам известен.
Кстати, если тип объекта Generic, задать тип не получится, но я использую интерфейсы, при этом реализация самого интерфейса Generic объектом не требуется, ведь Binding всё равно работает через рефлексию. Достаточно описать в интерфейсе "контракт" на заданный шаблон данных и можно делать и то и другое раздельно.
UserControl это путь в обратном направлении, это вынуждает нас привязывать Control к модели представления, что как по мне, не является полезным, перенести такой UserControl для работы в другом месте геморой или вообще будет невозможным.
+ UserControl это лишние элементы в визуальном дереве, сейчас направление в WPF именно на снижение размера визуального дерева, чтоб не было 100500 ContentPresenter'ов друг в друге.
+ не забывай, что UserControl и ContentControl, довольно низкоуровневые контролы, а иногда на много полезнее делать Visual Control'ы, где всё их навороты не очень то и нужны.

Но я ни кого не агитирующую, делай как считаешь нужным )
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
WPF: Не получается отобразить контент
    #39593317
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes,

Ну вот, я начал новый проект и стал применять твой подход с шаблонами, добавленными в ресурсы по ключам-типам. Тем более, что в 2017-й студии теперь визуализацию при редактировании xaml-а можно смотреть прямо в запущенном приложении.
В принципе удобно, оказывается для ItemsControl и TreeView можно даже и не задавать шаблон Item-а вообще - он его автоматом найдет в ресурсах по типу.

Но столкнулся с двумя проблемами. Во-первых почему-то нельзя для DataType задать не конкретный класс, а интерфейс. Ну то есть, задать-то можно, но он не обнаруживается для нужных классов

Во-вторых, не могу добавить в один словарь DataTemplate и HierarhicalDataTemplate с одинаковыми ключами. Можно, конечно, на разных уровнях их объявить, но это не очень удобно, к тому же ListView, к примеру, норовит забрать HierarhicalDataTemplate, если тот ему попадется первым.

Ты решал как-то эти проблемы или ты с ними не сталкивался?
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39593401
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.ProRoman Mejtes,

Ну вот, я начал новый проект и стал применять твой подход с шаблонами, добавленными в ресурсы по ключам-типам. Тем более, что в 2017-й студии теперь визуализацию при редактировании xaml-а можно смотреть прямо в запущенном приложении.
В принципе удобно, оказывается для ItemsControl и TreeView можно даже и не задавать шаблон Item-а вообще - он его автоматом найдет в ресурсах по типу.

Но столкнулся с двумя проблемами. Во-первых почему-то нельзя для DataType задать не конкретный класс, а интерфейс. Ну то есть, задать-то можно, но он не обнаруживается для нужных классов

Во-вторых, не могу добавить в один словарь DataTemplate и HierarhicalDataTemplate с одинаковыми ключами. Можно, конечно, на разных уровнях их объявить, но это не очень удобно, к тому же ListView, к примеру, норовит забрать HierarhicalDataTemplate, если тот ему попадется первым.

Ты решал как-то эти проблемы или ты с ними не сталкивался?

я не использую HierarhicalDataTemplate, для иерархии я использую DataTemplate'ы

Использовать такой подход повсеместно совсем необязательно .
Есть класс Person, есть шаблон с ключом {x:Type Person}, но если мне надо какой то отличный от стандартного шаблона, я просто указываю его явно и определяю с соответствующим именем. Стандартный тип для такого типа просто отображает, например, имя, фамилию и иконку.

Так же ресурсы можно переопределять в визуальном дереве. То есть в 1 месте ключ {x:Type Person} вернёт 1 шаблон, в другом другой. Поиск ресурсов лучше начинать с того контрола, для которого вы получаете шаблон.

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

Автоопределение я использую только в окнах, для классов наследованных от BaseWindowViewModel.
К слову, я даже не знал, что ListBox сам опредлят тип, потому, что всегда его указывал явно
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39593675
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtesя не использую HierarhicalDataTemplate, для иерархии я использую DataTemplate'ы
А это как? можно пример?
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39593713
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я так понял, просто реализация своего дерева на базе ItemsControl. Там же только контейнер по сути переписать надо - разворачивание добавить с иконкой. Так работает целый зоопарк TreeList-ов
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39593776
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры ПавловныRoman Mejtesя не использую HierarhicalDataTemplate, для иерархии я использую DataTemplate'ы
А это как? можно пример?
Я готовлю маленькую статью на эту тему :( готово процентов на 50, когда закончу пока не знаю, давно обещал
Суть в том, что на базе представления коллекции иерархия разворачивается в список, для отображения дерева можно использовать любые списочные контролы. То есть добавить дерево можно в combobox, listbox, datagrid с минимальными затратами и переработками. работает быстрее, поддерживает мультиселект, иерархические команды, вставку элементов в любую ветку и многое другое.
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39593820
Супер_Пав
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman MejtesСон Веры Павловныпропущено...

А это как? можно пример?
Я готовлю маленькую статью на эту тему :( готово процентов на 50, когда закончу пока не знаю, давно обещал
Суть в том, что на базе представления коллекции иерархия разворачивается в список, для отображения дерева можно использовать любые списочные контролы. То есть добавить дерево можно в combobox, listbox, datagrid с минимальными затратами и переработками. работает быстрее, поддерживает мультиселект, иерархические команды, вставку элементов в любую ветку и многое другое.
ждем =)
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39593897
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes,

Точно, обещал кому-то.
Не забудь здесь опубликовать )
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39595289
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes,
А вот тут наступил как раз на грабли с деревом.
Нужно сделать выбранным некоторый узел, при этом дерево с виртуализацией.
ItemContainerGenerator вернет для него null, если его нет на экране

В твоем случае (даже если дерево не использовать), в общем-то, суть не меняется.
Как ты выкручиваешься?
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39595623
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
я уже писал про эту багу, не очень в курсе про TreeView, но думаю там всё работает точно так же
Если включена виртуализация, то элементы списке ListBoxItem и TreeViewItem будут существовать только те, что находятся в области видимости (ViewPort) и элемент который находится в фокусе .
Я это обходил опять же через ICollectionView в котором использовались обёрточные классы для реализации IsSelected свойств, в нём указывал какой тип выделения используется и если это Single селект, то при выделении другого элемента он снимал выделение с ранее выделенного. По сути это дублирование операций в выделением, крайне неприятная реализация, так как вносит путаницу и при изменении типа выделения нужно контролировать в 2 местах этот параметр. По другому никак, либо отключать виртуализацию. Так как объекты находящиеся за рамками ViewPort'а не существуют , значит и их связывания с моделью не существуют. Такой вот неприятный баг.
Вот похожее описание вашей проблемы https://stackoverflow.com/questions/37541929/extended-selection-mode-virtualization-and-isselected-binding
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39595637
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman MejtesЯ это обходил опять же через ICollectionView в котором использовались обёрточные классы для реализации IsSelected свойств, в нём указывал какой тип выделения используется и если это Single селект, то при выделении другого элемента он снимал выделение с ранее выделенного.Вот это я не очень понял, IsSelected-то можно отработать по всякому, но как заставить ListBox перейти к этому элементу на экране.
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39606681
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman MejtesС интерфейсами не получится. GetType() возвращает конкретный тип, а не интерфейс. Это же касается и наследования, для таких случаев вам надо будет явно обозначить шаблон. При этом, вам не кто не запрещает в качестве ключа указать тип интерфейса. Если это действительно нужно.Хм, можно же сделать собственный TemplateSelector по идее, который будет петь и плясать искать шаблон на основе критерия интерфейса или даже обобщенного типа ))
...
Рейтинг: 0 / 0
WPF: Не получается отобразить контент
    #39611356
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtesиспользовались обёрточные классы для реализации IsSelected свойств, в нём указывал какой тип выделения используется и если это Single селект, то при выделении другого элемента он снимал выделение с ранее выделенного. По сути это дублирование операций в выделением, крайне неприятная реализация, так как вносит путаницу и при изменении типа выделения нужно контролировать в 2 местах этот параметр. По другому никакА может всё-таки "как"? Я вот такую штуку замутил, правда для восстановления состояния IsExpanded пока, но можно и к IsSelected прикрутить. Прелесть в том, что не нужен оберточный класс для каждой ноды. В общих чертах:
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
    <TreeView Name="Tv" stw:TreeViewItemStateWatcher.StateHolder="{Binding StateHolder}">
      <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
          <Setter Property="stw:Extender.Module">
            <Setter.Value>
              <stw:TreeViewItemStateWatcher Node="{Binding}" Holder="{Binding Path=(stw:TreeViewItemStateWatcher.StateHolder), ElementName=Tv}" />
            </Setter.Value>
          </Setter>
        </Style>
      </TreeView.ItemContainerStyle>
    </TreeView>


На объект дерева VM вешается некий класс StateHolder. Он хранит состояние IsExpanded для каждого VM-узла дерева, которое может быть любым object (по сути, это просто обертка для HasSet<object>). Он, соответственно, байндится на TreeView

Далее, на каждый TreeViewItem с помощью стиля и Attached-свойства вешается некий TreeViewItemStateWatcher, который и отслеживает состояние IsExpanded, забайндив это свойство на себя (в коде). Также ему дадена ссылка на StateHolder всего дерева и VM-объект текущего узла, поэтому он успешно и в обе стороны взаимодействует с этим StateHolder-ом.

То есть теперь у меня спокойно восстанавливается состояние узлов дерева, даже если его визуальное дерево пересоздается из шаблона, потому что состояние узлов теперь хранится в модели, а не в визуальном дереве. А также это корректно работает с виртуализацией, а также можно управлять состоянием через VM, не создавая оболочек для узлов.
...
Рейтинг: 0 / 0
19 сообщений из 19, страница 1 из 1
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / WPF: Не получается отобразить контент
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]