1

I have the following custom control,

public sealed class MediaFileItemControl : Control
{
    public static readonly DependencyProperty MediaFileProperty =
        DependencyProperty.Register(nameof(MediaFile), typeof(StorageFile), typeof(MediaFileItemControl), new PropertyMetadata(null));

    public MediaFileItemControl()
    {
        DefaultStyleKey = typeof(MediaFileItemControl);
    }

    public StorageFile MediaFile
    {
        get => (StorageFile)GetValue(MediaFileProperty);
        set => SetValue(MediaFileProperty, value);
    }
}

the following style for it,

<!-- Generic.xaml -->
<Style TargetType="controls:MediaFileItemControl" >
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controls:MediaFileItemControl">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{TemplateBinding MediaFile.Name}" />
                    <TextBlock Text="{TemplateBinding MediaFile.Path}" />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

and lastly, I want to use it within a ListBox, something like:

<ListBox ItemsSource="{x:Bind ViewModel.MediaFiles, Mode=OneWay}">
    <ListBox.ItemTemplate>
        <DataTemplate x:DataType="win_storage:StorageFile" xmlns:win_storage="using:Windows.Storage">
            <controls:MediaFileItemControl MediaFile="{x:Bind}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

However, when I build the project, I get the following error in Generic.xaml

The XAML Binary Format (XBF) generator reported syntax error '0x80004005'

Where is the syntax error and what is the right way to achieve what I want?

5
  • Simply define Setter.Value as <ControlTemplate><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding Name}" /><TextBlock Text="{Binding Path}" /></StackPanel></ControlTemplate> Commented Jan 7, 2024 at 15:45
  • This does not seem right. Let's assume that I have more then one property in the custom control, how will the style know Name is for which property? By the way, I tried what you suggested before. The syntax error goes away, but the binding still does not work. The list item is there but there is nothing visual. Commented Jan 7, 2024 at 15:51
  • I don't know how you tried, but it does work for me. Please post a reproducing project so we can fix it. Commented Jan 7, 2024 at 16:04
  • I apologise. I missed that in your suggestion you replaced TemplateBinding with Binding as well. Yes, this works. I am a bit confuse though because of the magic (dynamic binding) this entails. Is there a way to use x:Bind instead of Binding to get compile time check? Commented Jan 7, 2024 at 16:29
  • My guess is that TemplateBinding doesn't support multi-part paths. It's typically used to bind a property of a template part to the property of the templated control and it's the first time I see someone trying to bind it to a property of the property. Usually a binding or x:Bind to a list item is defined within a DataTemplate and a custom control should not be aware what item model someone is binding it to. You could put your MediaFileItemControl in the DataTemplate but, make MFIC derive from ContentControl and put the StackPanel + the bindings in the ListBox.ItemTemplate Commented Feb 17, 2024 at 18:51

1 Answer 1

1

x:Bind has lots of issues that are quite difficult to overcome: https://github.com/microsoft/microsoft-ui-xaml/issues/2508

But you can use a ContentControl that points to a DataTemplate. So in your case, you can write it like this:

<ResourceDictionary
    x:Class="MyWinUIApp.ResourceDictionary1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyWinUIApp"
    xmlns:storage="using:Windows.Storage">

    <DataTemplate x:Key="StorageFileTemplate" x:DataType="storage:StorageFile">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{x:Bind Name}" />
            <TextBlock Text="{x:Bind Path}" />
        </StackPanel>
    </DataTemplate>

    <Style TargetType="local:MediaFileItemControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <ContentControl ContentTemplate="{StaticResource StorageFileTemplate}" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

Note I've create a custom ResourceDictionary as it doesn't seen to work in the App.xaml one for another mysterious reason. Make sure you create one with a code-behind to support x:Bind as explained here: Resource dictionaries with {x:Bind}

If you don't want that complexity, you can still use the ole Binding markup extension wich often works where the so-called "better" x:Bind fails:

<Style TargetType="local:MediaFileItemControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Name}" />
                    <TextBlock Text="{Binding Path}" />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Simon. I think I will avoid the complexity and go with the good old Binding. Although I think my requirement (I have more to do with the control than a single property) is better achieved by a User Control.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.