Я не могу найти, как легко создать собственный элемент управления, в который можно вставлять контент в xaml. Например, я хотел бы, чтобы мой элемент управления содержал сетку, которую я каким-то образом стилизую, а затем вставляю в нее контент извне компонента.
<local:MyComponent>
... some xaml content
</local:MyComponent>
Моя идея заключалась в том, чтобы был какой-то заполнитель, указывающий, куда поместить контент. Но, вероятно, будет иначе.
<UserControl>
<Grid>
<ContentPlaceholder />
</Grid>
</UserControl>





Позвольте мне показать вам два примера:
Пример А
Создайте собственный элемент управления и добавьте DependencyProperty для своего контента. Вам также необходимо добавить атрибут ContentProperty, чтобы можно было задать содержимое в XAML.
CustomControl.cs
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
namespace CustomContentControlExample;
[ContentProperty(Name = "Content")]
public sealed class CustomControl : Control
{
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(
nameof(Content),
typeof(object),
typeof(CustomControl),
new PropertyMetadata(default));
public CustomControl()
{
this.DefaultStyleKey = typeof(CustomControl);
}
public object Content
{
get => GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
}
Общий.xaml
<Style TargetType = "local:CustomControl">
<Setter Property = "Template">
<Setter.Value>
<ControlTemplate TargetType = "local:CustomControl">
<ContentPresenter Content = "{TemplateBinding Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Пример Б
Создайте пользовательский элемент управления, который наследуется от ContentControl.
CustomContentControl.cs
using Microsoft.UI.Xaml.Controls;
namespace CustomContentControlExample;
public sealed class CustomContentControl : ContentControl
{
public CustomContentControl()
{
this.DefaultStyleKey = typeof(CustomContentControl);
}
}
Общий.xaml
<Style TargetType = "local:CustomContentControl">
<Setter Property = "Template">
<Setter.Value>
<ControlTemplate TargetType = "local:CustomContentControl">
<ContentPresenter Content = "{TemplateBinding Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
ОБНОВЛЯТЬ
Если вы не хотите иметь Style в Generic.xaml, вы можете создать файл ResourceDictionary:
CustomContentControl.xaml
<ResourceDictionary
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "using:CustomContentControlExample">
<Style TargetType = "local:CustomControl">
<Setter Property = "Template">
<Setter.Value>
<ControlTemplate TargetType = "local:CustomControl">
<ContentPresenter Content = "{TemplateBinding Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
и добавьте ResourceDictionary в Generic.xaml или App.xaml:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source = "CustomControl.xaml" />
</ResourceDictionary.MergedDictionaries>
Обновите мой ответ. Надеюсь, поможет.
Большое спасибо за ваше время и предложения. Я нашел решение, которое работает для меня (см. Последний пост). Надеюсь, это решение правильное.
Такой контроль уже есть. Это называется ContentControl. У него есть свойство Content, которое вы можете установить для любого содержимого XAML. Затем вы можете использовать свойство Template, чтобы определить ControlTemplate с окружающим Grid, например:
<ContentControl>
<ContentControl.Template>
<ControlTemplate TargetType = "ContentControl">
<Grid Background = "Yellow">
<ContentPresenter />
</Grid>
</ControlTemplate>
</ContentControl.Template>
<ContentControl.Content>
<!-- Some XAML content: -->
<TextBlock>some content...</TextBlock>
</ContentControl.Content>
</ContentControl>
Чтобы иметь возможность повторно использовать ContentTemplate, вы можете сохранить его как ресурс в словаре ресурсов. Например, в App.xaml:
<?xml version = "1.0" encoding = "utf-8"?>
<Application
x:Class = "App1.App"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "using:App1">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns = "using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<ControlTemplate x:Key = "gridTemplate" TargetType = "ContentControl">
<Grid Background = "Yellow">
<ContentPresenter />
</Grid>
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
Использование:
<ContentControl Template = "{StaticResource gridTemplate}">
<!-- Some XAML content: -->
<TextBlock>some content...</TextBlock>
</ContentControl>
Вы также можете установить свойство Content для любого объекта и использовать свойство ContentTemplate для определения внешнего вида этого объекта.
Большое спасибо, это прекрасно работает. Можно ли использовать ContentControl для создания пользовательского компонента вместо UserControl? Я хотел бы иметь компонент с настраиваемым содержимым, а также кодом C#. Как и в случае, когда я создаю собственный элемент управления (код xaml + .cs).
Если я правильно понимаю ваш вопрос, вы можете создать собственный класс, который наследуется от ContentControl, а затем добавить к нему любой пользовательский класс.
Большое спасибо за ваше время и предложения. Я нашел решение, которое работает для меня (см. Последний пост). Надеюсь, это решение правильное.
Спасибо всем за опубликованные решения. Все они помогли мне найти нужное мне решение.
В итоге я создал отдельный компонент контента следующим образом:
MyContentControl.xaml.cs
using Microsoft.UI.Xaml.Controls;
namespace winui_3_app.components;
public sealed partial class MyContentControl : ContentControl
{
public MyContentControl()
{
this.InitializeComponent();
}
}
MyContentControl.xaml
<ContentControl
x:Class = "winui_3_app.components.MyContentControl"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local = "using:winui_3_app.components"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable = "d">
<ContentControl.Template>
<ControlTemplate TargetType = "ContentControl">
// Content decoration
<Grid Background = "Yellow" Padding = "10, 10, 10, 10">
<ContentPresenter />
</Grid>
</ControlTemplate>
</ContentControl.Template>
// Content placeholder
<ContentControl.Content />
</ContentControl>
Использование компонента
<?xml version = "1.0" encoding = "utf-8"?>
<Window
x:Class = "winui_3_app.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local = "using:winui_3_app.components"
mc:Ignorable = "d">
<Grid>
<local:MyContentControl>
// Some content
<TextBlock>Hello!</TextBlock>
</local:MyContentControl>
</Grid>
</Window>
Спасибо за образец, все работает отлично. Можно ли разместить код xaml из Generic.xaml в специальном файле, привязанном к CS-файлу компонента? Я хочу сказать, что компонент не имеет части кода в глобальном файле и поэтому отделен.