【问题标题】:Click handler of button in datatemplate not working单击数据模板中按钮的处理程序不起作用
【发布时间】:2020-09-24 12:52:12
【问题描述】:

我有一个结合了许多数据模板的资源字典。我将此资源字典作为ResourceDictionary.MergedDictionaries 包含在我的Page.Resources 中。我的数据模板之一是ListView,虽然项目源和项目点击工作正常,但在数据模板中设置的ListViewItem 上的单独按钮没有调用我的点击方法。我不确定是否正确设置。

这个点击方法是在类后面的代码中定义的,它定义了页面 Xaml,包括资源字典并使用我的 ListViewItems 的数据模板。

  • 字典

    • DataTemplates.xaml Click="MyPages_ClickMethod"
  • 页面

    • MyPage.xaml
    • MyPage.xaml.cs MyPages_ClickMethod()

这是我在数据模板中设置按钮的方式:

<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/sharePlusIcon@2x.png" VerticalAlignment="Center" HorizontalAlignment="Center">
    </Image>
</Button>

不使用 ICommand 是否可以做到这一点?

类似:Click="{x:Bind Path=pages:ProductPage.MultiShareSelectFileButton_Click}",但这是在抱怨 MultiShareSelectFileButton_Click 应该是静态的

【问题讨论】:

    标签: c# xaml uwp


    【解决方案1】:

    我会马上解决的。问题来了,

    您的DataTemplate 在资源字典中。如果可以的话,资源字典是为样式和转换器制作的。不建议将DataTemplate 放入资源字典中。

    为什么不推荐?

    1. 原因很直接,资源字典是用来放全局数据的。例如:您可能希望在您的应用程序或经常使用的转换器中可用的控件样式。
    2. 这是因为通常您会在您的app.xaml 中定义资源字典,该字典会在您的启动画面出现时运行。
    3. 现在,如果您有很多东西(DataTemplates、Styles、Converters)都定义到资源字典中,并合并到app.xaml&lt;Application.ResourceDictionary&gt; 部分,这将对您的应用程序启动时间产生重大影响,这将破坏您的用户体验。

    有什么建议?

    1. 建议不要让您的转换器和样式全局化,除非您到处都需要它们。例如:如果您有一个 BoolToVisibilityConverterCustomRoundButtonStyle,您只在 4 个中的一个 page/userControl 上使用。那么为其他 3 个页面加载样式或转换器是没有意义的。所以你应该在&lt;Page.Resources&gt; 中声明它们。
    2. 同样适用于您的DataTemplate,如果您只想使用一次,为什么要全局声明它。而是将其声明给您的&lt;Page.Resources&gt;。您的问题将立即得到解决,因为您的 Page 将有一个代码隐藏,因此您的 xaml 将知道在哪里寻找该方法。这就是事情出错的地方。

    但是,如果您有一个 DataTemplate 可用于以下所有视图,则您的解决方案是:

    您的解决方案:

    如果您必须在资源字典中使用它,请使用 {x:Bind} 和 x:DataType="Models:YourDataContextModel" 将您的 DataTemplate 绑定到您的模型。这样,您的 xaml 将确切知道在何处查找单击方法。

    下面是它的一个示例:

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

    在哪里 YourModel 存在于在 xaml 中定义为“yourDefinedNameSpace”的namespace 中,它包含一个签名方法:internal void GoFetchData()

    我希望这会有所帮助。如果您有任何疑问,请随时使用 cmets 部分

    【讨论】:

    • 模型的internal void签名是否可以在ViewController上实现,即xaml.cs。我可以让这个 xBind 指向特定于正在查看的页面的方法的实现吗?
    • 没有。您无法 x:bind 具有不同 DataContext(模型)的数据模板具有 x:bind 甚至绑定到正在查看的页面后面的代码。有一些替代方法,例如不将数据模板放在资源字典中,而是将其放在 page.resources 中或向上查看 Visual 树(完全不推荐)并制作同样不推荐的静态方法。一种方法是将数据模板绑定到视图模型,但随后它取出了 MVVM 的核心原则,因此是代码异味
    • 如果它是您想要绑定到的代码,并且您仍然希望保留您的数据模板资源字典。有一种方法,但它是一种方法而不是理想的方法,我将使用一个示例进行解释,我在数据模板中有一个类似的按钮,我无权访问模型。所以我把按钮放在一个控件中,让控件接受一个具有基本属性的 ILikable 接口,我需要发布一个like,并使用事件传输数据。我把喜欢的代码放在likeButtonControl代码后面。现在我有一个独立于我所有其他代码的类似控件。
    • 数据模板也可以用作全局资源。如果您想在不同的页面上显示相同的模板怎么办?另外,如果你只在一个地方使用转换器,那么有什么意义呢?我从未见过样式和资源在启动期间会减慢应用程序的速度。如果应用启动缓慢,则很可能涉及其他问题。
    • 嗯...我刚刚尝试在 App.xaml 中包含 2MB+ 资源字典文件并引用它们,但我的应用程序启动速度一样快。
    【解决方案2】:

    我发现Xaml中也需要指定ClickMode="Press"。

    <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 .}" />
    

    我不记得过去必须这样做,但是在花费数小时进行故障排除、将 RelayCommand 转换为 IAsyncCommand 等之后,这是唯一有效的方法。事实上,除非我包含 ClickMode="Press",否则我什至无法触发常规的代码隐藏“点击事件”方法!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多