0

I have a resource dictionary combining a number of datatemplates. I'm including this resource dictionary as a ResourceDictionary.MergedDictionaries in my Page.Resources. One of my datatemplates is a ListView and while the item source and item click is working correctly, a separate button on the ListViewItem, set in the datatemplate, is not calling my click method. Im unsure about setting this up correctly.

This click method is defined in the code behind class the defines the pages Xaml including the resource dictionary and using my datatemplate for ListViewItems.

  • Dictionaries

    • DataTemplates.xaml <- ListView template here with a button click defined in the page cs, i.e. Click="MyPages_ClickMethod"
  • Pages

    • MyPage.xaml
    • MyPage.xaml.cs <- click method defined here, MyPages_ClickMethod()

Here is how I am setting up the button in the datatemplate:

<Button Tag="{Binding id}" Click="MultiShareSelectFileButton_Click" Background="Transparent" Visibility="{Binding multiShareSelected, Converter={StaticResource BooleanToVisibilityConverter}, ConverterParameter=Inverted, Mode=OneWay}"> <Image Width="27" Source="ms-appx:///Assets/[email protected]" VerticalAlignment="Center" HorizontalAlignment="Center"> </Image> </Button> 

Is it possible to do this without using ICommand?

Something like: Click="{x:Bind Path=pages:ProductPage.MultiShareSelectFileButton_Click}", but this is complaining that MultiShareSelectFileButton_Click should be static

2 Answers 2

2

I'll get right to it. Here is the issue,

Your DataTemplate is in a resource dictionary. The resource dictionary is made for styles and converters if I may. Putting the DataTemplate in a resource dictionary is not recommended.

Why isn't it recommended?

  1. The reason is straight, resource dictionaries are used to put global data. For ex: a control style that you might want to be available through out your app or your converters which are being used frequently.
  2. This is because generally you would define the resource dictionary in your app.xaml which runs when your splashscreen appears.
  3. Now if you have a lot of stuff (DataTemplates, Styles, Converters) all defined into resource dictionaries that are merged in <Application.ResourceDictionary> part of app.xaml, it's gonna have a significant impact on your app launch time, which will spoil your user's experience.

What's advised?

  1. It's advised to keep your converters and styles not global unless you need them everywhere. For example: If you have a BoolToVisibilityConverter or a CustomRoundButtonStyle which you use only on one page/userControl out of 4. Then it doesn't make sense to load the style or converter for the other 3 Pages. So you should declare them in <Page.Resources> instead.
  2. Same for your DataTemplate why declare it globally if you want to use it just once. Rather declare it to your <Page.Resources>. Your problem will be solved immediately as your Page will have a code-behind, so your xaml will know where to look for the method. That's where things are going wrong.

But in-case you have a single DataTemplate to be used on all your Views below is your solution:

Your Solution:

In-case you have to use it in a resource dictionary, use {x:Bind} and x:DataType="Models:YourDataContextModel" to bind your DataTemplate to your model. this ways your xaml will know exactly where to look for the method on click.

Below is a sample of it:

 <DataTemplate x:Key="HelloTemplate" x:DataType="yourDefinedNameSpace:YourModel"> <Button Click="{x:Bind GoFetchData}"/> </DataTemplate> 

Where YourModel exists in a namespace defined as "yourDefinedNameSpace" in xaml and it contains a method of signature: internal void GoFetchData()

I hope this helps. Feel free to use the comments section if you have any doubts

Sign up to request clarification or add additional context in comments.

8 Comments

Would the internal void signature of the Model be implementable on the ViewController, i.e. xaml.cs. Can I have this xBind point to the implementation of the method specific to the page being viewed?
No. There is no way you can x:bind a data template with a different DataContext (a model) to have an x:bind or even binding to the code behind of the page being viewed. There are alternatives like not putting your data template in a resource dictionary instead putting it in page.resources or going up the Visual tree (completely not recommended) and making a static method which is also not recommended. One way is that you bind the data template to a viewmodel but then it takes out the core principles of MVVM and hence is a code smell
If it is the code behind you want to bind to and you do still want to keep your data Template resource dictionary. There is one way but it is a way round and not the ideal way, I'll explain it using an example, I have a like button that is in a data Template and I don't have access to the model. So I put the button in a control and make the control accept an ILikable interface that has the basic properties I need to post a like and I transfer data using events. I put the code to like in the likeButtonControl code behind. Now I have a like control independent of all my other code.
Data templates can be used as global resources too. What if you want to display the same template across different pages? Also, what's the point of having a converter if you only use it in one place? I have never seen styles and resources slow the app during start up. If the app starts up slow, it's most likely something else involved.
Hmm... I just tried including 2MB+ resource dictionary files n referencing them in App.xaml, my app starts just as fast though.
|
0

I found that it was also necessary to specify ClickMode="Press" in Xaml.

<Button Content="&#xE16F;" Focusable="True" FontFamily="Segoe UI Symbol" FontSize="16" Background="{StaticResource HeroLightGray}" Foreground="Black" HorizontalAlignment="Center" VerticalAlignment="Center" ClickMode="Press" Command="{Binding DataContext.CopyMetadataSourceAsync, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" CommandParameter="{Binding .}" /> 

I do not recall having to do this in the past, but after spending hours troubleshooting, converting RelayCommand to IAsyncCommand, etc. this is the only thing that worked. In fact, I couldn't even get a regular code-behind "Click event" method to fire unless I included that ClickMode="Press"!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.