我可以将这块XAML变成可重复使用的“控件”吗?

时间:2017-04-28 13:57:21

标签: c# wpf

我有一个Grid,在那个网格中,我有这个:

<StackPanel Grid.Row="2"
            Grid.Column="0">
    <Grid x:Name="GridButtonItem" Margin="30,0,0,5">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.Style>
        <Style TargetType="{x:Type Grid}">
            <Setter Property="Background"
                Value="Transparent" />
            <Style.Triggers>
            <Trigger Property="IsMouseOver"
                 Value="True">
                <Setter Property="Background"
                    Value="#332a8dd4" />
            </Trigger>
            <Trigger Property="IsMouseOver"
                 Value="False">
                <Setter Property="Background"
                    Value="Transparent" />
            </Trigger>
            </Style.Triggers>
        </Style>
        </Grid.Style>
        <Image Grid.Row="0"
           Grid.RowSpan="2"
           Grid.Column="0"
           Margin="3"
           Source="{dx:DXImageOffice2013 Image=Windows_32x32.png}"
           HorizontalAlignment="Center"
           VerticalAlignment="Center" />
        <TextBlock Grid.Row="0"
               Grid.Column="1"
               Margin="10,3,3,0"
               Text="Application Log" />
        <TextBlock Grid.Row="1"
               Grid.Column="1"
               Margin="10,0,3,3"
               Text="C:\Program Files (x86)\ATI Technologies\ATI.ACE\MOM-InstallProxy" />
    </Grid>
</StackPanel>

StackPanel实际上意味着拥有许多GridButtonItem项。有没有办法可以以某种方式制作GridButtonItem的“模板”,然后为每个我要添加到StackPanel的模板,只需设置图像和文本属性?

像这样的东西(只是用于演示的伪代码):

<StackPanel>
    <Grid Template="myGridItemTemplate">
        <Setter Property="Image" Value="img1.png"/>
        <Setter Property="Text1" Value="button1 Text"/>
        <Setter Property="Text2" Value="button2 Text"/>
    </Grid>
    <Grid Template="myGridItemTemplate">
        <Setter Property="Image" Value="img1.png"/>
        <Setter Property="Text1" Value="button1 Text"/>
        <Setter Property="Text2" Value="button2 Text"/>
    </Grid>
    <Grid Template="myGridItemTemplate">
        <Setter Property="Image" Value="img1.png"/>
        <Setter Property="Text1" Value="button1 Text"/>
        <Setter Property="Text2" Value="button2 Text"/>
    </Grid>
</StackPanel>

因此,添加的每一个都会获取行/列定义,以及嵌入的Image和两个TextBlock。然后我只为每一个添加了三个属性。

这可能吗?

2 个答案:

答案 0 :(得分:1)

您可以将网格控件放入UserControl,然后在整个项目中重复使用UserControl。我有一个简单的例子,用标签和文本框这样做。

这是XAML:

<UserControl x:Class="TestVision.CustomControls.LabelAndTextbox"
             x:Name="parent"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:TestVision.CustomControls"
             mc:Ignorable="d" >
    <StackPanel Orientation="Horizontal" DataContext="{Binding ElementName=parent}">
        <TextBlock Text="{Binding Path=Label}" Width="{Binding Path=LabelWidth}" VerticalAlignment="Center" TextAlignment="Right" Margin="0,0,10,0" Height="22"/>
        <TextBox Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}" Width="{Binding Path=TextboxWidth}" IsReadOnly="{Binding Path=TextboxReadOnly, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalContentAlignment="{Binding Path=TextboxHorizontalContentAlgnment}"/>
    </StackPanel>
</UserControl>

您希望能够设置的任何属性,例如您的图像文本等必须绑定到后面代码中的依赖项属性。 代码背后:

 public partial class LabelAndTextbox : UserControl
    {
        /// <summary>
        /// Gets or sets the Label which is displayed next to the field
        /// </summary>
        public String Label
        {
            get { return (String)GetValue(LabelContent); }
            set { SetValue(LabelContent, value); }
        }

        /// <summary>
        /// Identified the Label dependency property
        /// </summary>
        public static readonly DependencyProperty LabelContent =
            DependencyProperty.Register("Label", typeof(string),
              typeof(LabelAndTextbox), new PropertyMetadata(""));

        public object Text
        {
            get { return (object)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }


        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(object),
              typeof(LabelAndTextbox), new PropertyMetadata(null));

        public Double LabelWidth
        {
            get { return (Double)GetValue(LabelWidthProperty); }
            set { SetValue(LabelWidthProperty, value); }
        }

        public static readonly DependencyProperty LabelWidthProperty =
            DependencyProperty.Register("LabelWidth", typeof(Double),
                typeof(LabelAndTextbox), new PropertyMetadata());

        public Double TextboxWidth
        {
            get { return (Double)GetValue(TextboxWidthProperty); }
            set { SetValue(TextboxWidthProperty, value); }
        }

        public static readonly DependencyProperty TextboxWidthProperty =
           DependencyProperty.Register("TextboxWidth", typeof(Double),
                 typeof(LabelAndTextbox), new PropertyMetadata());

        public bool TextboxReadOnly
        {
            get { return (bool)GetValue(TextboxReadOnlyProperty); }
            set { SetValue(TextboxReadOnlyProperty, value); }
        }


        public static readonly DependencyProperty TextboxReadOnlyProperty =
            DependencyProperty.Register("TextboxReadOnly", typeof(bool),
              typeof(LabelAndTextbox), new FrameworkPropertyMetadata());

        public HorizontalAlignment TextboxHorizontalContentAlgnment
        {
            get { return (HorizontalAlignment)GetValue(TextboxHorizontalContentAlgnmentProperty); }
            set { SetValue(TextboxHorizontalContentAlgnmentProperty, value); }
        }


        public static readonly DependencyProperty TextboxHorizontalContentAlgnmentProperty =
            DependencyProperty.Register("TextboxHorizontalContentAlgnment", typeof(HorizontalAlignment),
              typeof(LabelAndTextbox), new FrameworkPropertyMetadata());

        public LabelAndTextbox()
        {
            InitializeComponent();
        }
    }

然后,您需要在XAML文件中向UserControl添加一个引用,如下所示:

xmlns:Resource="clr-namespace:ProjectNamespace.FolderContainingYourControl"

资源是一个通用标识符,您可以根据需要调用它,然后您可以像这样引用您的控件:

 <Resource:LabelAndTextblock x:Name="AddressLine1" Label="{Binding LblTxt_AddressLine1}" Text="{Binding AddressLine1, Mode=TwoWay}" Margin="10,5,0,5" LabelWidth="70" TextWidth="250" TextHeight="60"/>

答案 1 :(得分:1)

您可以使用UserControl(两种不同的方式)或DataTemplate来执行此操作。让我们一起去DataTemplate,因为stuicidle已经巧妙地展示了一种UserControl方法。

使用DataTemplate也有几种不同的方法。

我们将做一些名为隐式 DataTemplate的事情。它是在Resources中创建的,但它没有x:Key属性,只有DataType="{x:Type local:GridItemViewModel}"属性。这将是这样的:只要DataTemplate在范围内,只要XAML需要显示GridItemViewModel并且没有任何东西指定要显示它的模板,它就会使用该隐式模板。

清除泥土!欢迎来到XAML学习曲线。

ViewModels.cs

using System;
using System.ComponentModel;
using System.Windows.Media;

namespace GridItemAnswer
{
    #region ViewModelBase Class
    public class ViewModelBase : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null) =>
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        #endregion INotifyPropertyChanged
    }
    #endregion ViewModelBase Class

    #region GridItemViewModel Class
    public class GridItemViewModel : ViewModelBase
    {
        #region LabelText Property
        private String _labelText = null;
        public String LabelText
        {
            get { return _labelText; }
            set
            {
                if (value != _labelText)
                {
                    _labelText = value;
                    OnPropertyChanged();
                }
            }
        }
        #endregion LabelText Property

        #region Path Property
        private String _path = null;
        public String Path
        {
            get { return _path; }
            set
            {
                if (value != _path)
                {
                    _path = value;
                    OnPropertyChanged();
                }
            }
        }
        #endregion Path Property

        #region ImageSource Property
        private ImageSource _imageSource = null;
        public ImageSource ImageSource
        {
            get { return _imageSource; }
            set
            {
                if (value != _imageSource)
                {
                    _imageSource = value;
                    OnPropertyChanged();
                }
            }
        }
        #endregion ImageSource Property
    }
    #endregion GridItemViewModel Class
}

MainWindow.xaml

<Window 
    x:Class="GridItemAnswer.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="clr-namespace:GridItemAnswer"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525"
    >
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:GridItemViewModel}">
            <StackPanel>
                <Grid x:Name="GridButtonItem" Margin="30,0,0,5">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="auto" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Grid.Style>
                    <Style TargetType="{x:Type Grid}">
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Background" Value="#332a8dd4" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                    </Grid.Style>
                    <Image 
                        Grid.Row="0"
                        Grid.RowSpan="2"
                        Grid.Column="0"
                        Margin="3"
                        Source="{Binding Image}"
                        HorizontalAlignment="Center"
                        VerticalAlignment="Center" 
                        />
                    <TextBlock 
                        Grid.Row="0"
                        Grid.Column="1"
                        Margin="10,3,3,0"
                        Text="{Binding LabelText}"
                        />
                    <TextBlock 
                        Grid.Row="1"
                        Grid.Column="1"
                        Margin="10,0,3,3"
                        Text="{Binding Path}"
                        />
                </Grid>
            </StackPanel> 
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <StackPanel>
            <ItemsControl>
                <local:GridItemViewModel
                    LabelText="Foo Bar"
                    Path="c:\foo\bar"
                    />
                <local:GridItemViewModel
                    LabelText="Baz Planxty"
                    Path="c:\baz\planxty"
                    />
            </ItemsControl>
            <Label>
                <local:GridItemViewModel
                    LabelText="A frog walks into a bank asking for a loan"
                    Path="c:\knick\knack"
                    />
            </Label>
        </StackPanel>
    </Grid>
</Window>