UserControl多个datatemplate + templateselector

时间:2015-12-11 16:21:03

标签: wpf user-controls datatemplate

我需要根据标志以不同的方式在usercontrol中显示数据。

为了达到这个目的,我尝试了以下方法,但在主视图中使用此控件时没有显示任何内容。

<UserControl DataContext="**self**">   
 <UserControl.Resources>       
    <DataTemplate x:Key="mouseInputTemplate">
            <TextBlock HorizontalAlignment="Center"><Run Text="{Binding Text}" /></TextBlock>
    </DataTemplate>

    <DataTemplate x:Key="touchInputTemplate">
        <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <Image Source="{Binding ImageUri}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                    Width="{Binding ImageWidth}" Height="{Binding ImageHeight}" />
            <TextBlock HorizontalAlignment="Center"><Run Text="{Binding Text}" /></TextBlock>
        </StackPanel>
    </DataTemplate>

    <local:InputModeDataTemplateSelector x:Key="inputModeTemplateSelector"
            MouseInputModeTemplate="{StaticResource mouseInputTemplate}"
            TouchInputModeTemplate="{StaticResource touchInputTemplate}" />
</UserControl.Resources>

<ContentControl HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalAlignment="Stretch"
        VerticalContentAlignment="Stretch" ContentTemplateSelector="{StaticResource inputModeTemplateSelector}" />
</UserControl>

我做错了什么? 有没有更好的方法来实现这一目标?

2 个答案:

答案 0 :(得分:1)

您的ContentPresenter想法是使用DataTemplateSelector执行此操作的正确方法,我应该自己考虑一下。

但是,这是另一种方法,与我的第一个答案不同,它实际上解决了你所遇到的所有问题:

XAML(实际上,Style可能会在单独的ResourceDictionary中定义):

<Window 
    x:Class="TestApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestApplication"
    xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
    Title="MainWindow" Height="350" Width="525"
    >
    <Window.Resources>
        <Style TargetType="local:TestControl">
            <Setter Property="Background" Value="Gainsboro" />
            <Style.Triggers>
                <!-- The 0 value for the InputMode enum is Mouse, so this will be the default. -->
                <Trigger Property="InputMode" Value="Mouse">
                    <Setter Property="Background" Value="Wheat" />
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type local:TestControl}">
                                <Grid Background="{TemplateBinding Background}">
                                    <TextBlock HorizontalAlignment="Center"><Run Text="{TemplateBinding Text}" /></TextBlock>
                                </Grid>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Trigger>
                <Trigger Property="InputMode" Value="Touch">
                    <Setter Property="Background" Value="LightSkyBlue" />
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type local:TestControl}">
                                <Grid Background="{TemplateBinding Background}">
                                    <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                                        <Image 
                                            Source="{TemplateBinding ImageUri}" 
                                            HorizontalAlignment="Stretch" 
                                            VerticalAlignment="Stretch"
                                            Width="{TemplateBinding ImageWidth}" 
                                            Height="{TemplateBinding ImageHeight}" 
                                            />
                                        <TextBlock HorizontalAlignment="Center"><Run Text="{TemplateBinding Text}" /></TextBlock>
                                    </StackPanel>
                                </Grid>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

    <Grid>
        <local:TestControl
            ImageHeight="100"
            ImageWidth="100"
            Text="This is the test control"
            ImageUri="http://www.optimizeagency.com/wp-content/uploads/2015/09/GoogleLogo.jpg"
            />
    </Grid>
</Window>

C#:

using System;
using System.Windows;
using System.Windows.Controls;

namespace TestApplication
{
    class TestControl : Control
    {
        public TestControl()
        {
            //  If input mode may change at runtime, you'll need an event that fires when that 
            //  happens and updates this property. 
            //  UIUtilities.GetInputMode() is just a stub in this example. 
            InputMode = UIUtilities.GetInputMode();
        }

        #region InputMode Property
        public InputMode InputMode
        {
            get { return (InputMode)GetValue(InputModeProperty); }
            set { SetValue(InputModeProperty, value); }
        }

        public static readonly DependencyProperty InputModeProperty =
            DependencyProperty.Register("InputMode", typeof(InputMode), typeof(TestControl),
                new PropertyMetadata(InputMode.Mouse));
        #endregion InputMode Property


        #region Text Property
        public String Text
        {
            get { return (String)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(String), typeof(TestControl),
                new PropertyMetadata(null));
        #endregion Text Property

        #region ImageUri Property
        //  The TemplateBinding in the template can't coerce a string to an 
        //  ImageSource, so we have to make that happen elsewhere. 
        public ImageSource ImageUri
        {
            get { return (ImageSource)GetValue(ImageUriProperty); }
            set { SetValue(ImageUriProperty, value); }
        }

        public static readonly DependencyProperty ImageUriProperty =
            DependencyProperty.Register("ImageUri", typeof(ImageSource), typeof(TestControl),
                new PropertyMetadata(null));
        #endregion ImageUri Property

        #region ImageHeight Property
        public float ImageHeight
        {
            get { return (float)GetValue(ImageHeightProperty); }
            set { SetValue(ImageHeightProperty, value); }
        }

        public static readonly DependencyProperty ImageHeightProperty =
            DependencyProperty.Register("ImageHeight", typeof(float), typeof(TestControl),
                new PropertyMetadata(float.NaN));
        #endregion ImageHeight Property

        #region ImageWidth Property
        public float ImageWidth
        {
            get { return (float)GetValue(ImageWidthProperty); }
            set { SetValue(ImageWidthProperty, value); }
        }

        public static readonly DependencyProperty ImageWidthProperty =
            DependencyProperty.Register("ImageWidth", typeof(float), typeof(TestControl),
                new PropertyMetadata(float.NaN));
        #endregion ImageWidth Property
    }

    #region This stuff belongs in a different file
    public static class UIUtilities
    {
        public static InputMode GetInputMode()
        {
            //  Here you'd do whatever you're already doing to detect the input mode
            return InputMode.Touch;
        }
    }

    public enum InputMode
    {
        Mouse,
        Touch
    }
    #endregion This stuff belongs in a different file
}

答案 1 :(得分:1)

感谢EdPlunkett和更多研究我发现它更好 在这里使用ContentPresenter而不是像这样绑定DataContext=this绑定(就像编写UserControl时建议的那样)

DataContext="{Binding RelativeSource={RelativeSource FindAncestor, 
                            AncestorType={x:Type yourType}}}"

代码:

 <UserControl.Resources>
        <DataTemplate x:Key="touchInputTemplate">
            <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                <Image Source="{Binding ImageUri}" Width="64" Height="64" />
                <TextBlock HorizontalAlignment="Center" Text="{Binding Text}" />
            </StackPanel>
        </DataTemplate>

        <DataTemplate x:Key="mouseInputTemplate">
            <TextBlock HorizontalAlignment="Center" Text="{Binding Text}" />
        </DataTemplate>

        <local:InputModeDataTemplateSelector x:Key="inputModeTemplateSelector"
                MouseInputModeTemplate="{StaticResource mouseInputTemplate}"
                TouchInputModeTemplate="{StaticResource touchInputTemplate}" />
    </UserControl.Resources>

<Grid DataContext="{Binding RelativeSource={RelativeSource FindAncestor, 
                                AncestorType={x:Type yourType}}}">
        <ContentPresenter Content="{Binding}" ContentTemplateSelector="{StaticResource inputModeTemplateSelector}">
</Grid>