制作(创建)可重用的动态视图 [英] Make (create) reusable dynamic Views

查看:31
本文介绍了制作(创建)可重用的动态视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Out 团队希望创建可重复使用的样式化视图.例如,我们希望在不同的应用程序中重用 CommonPromptView(我们自己的、可自定义的对话框,我们可以在其中隐藏取消"按钮、设置标题、显示特定图标等).

Out team wants to create reusable, stylable Views. For example, we want to reuse in different apps the CommonPromptView (our own, customizable dialog box where we can hide "Cancel" button, set the header, show specific icon and so on).

该视图的表面有几个元素:TextBlocks、Buttons.我们想让它们风格化.

That view has several elements on it's surface: TextBlocks, Buttons. We want to make them stylable to.

那么,解决此任务的最佳方法是什么?

Well, what is the best approach to solve this task?

  1. 视图可以是窗口类型.
  2. 视图可以是 UserControl 类型.

在第一种情况下,可以通过两种方式支持样式:

In the first case, styling can be supported in two ways:

  1. 元素的样式引用了 DynamicResources.
  2. 样式被传递给视图的构造函数.

两者都不干净(在我看来).

The both are not clean (in my opinion).

但是如果一个视图是一个用户控件,那么每次创建新应用程序的人都必须创建一个新窗口来包含一个用户控件,并将它的绑定设置为正确的 DP(样式类型).此外,如果一个 UserControl 有它自己的非常方便的 API(最常用操作的静态方法),对于包含 UserControl 的 Window 的用户来说,这些 API 将会丢失.

But if a View is a UserControl, then each time somebody who creates new app has to create a new Window to contain a UserControl and set it's bindings to DPs (of Style type) properly. Besides, if a UserControl has it's own very convinient API (static methods for the most frequently used operations) which will be lost for the user of the Window which contains the UserControl.

更新

作为 UserControl 实现的 CommonPromptView 示例.

Example of CommonPromptView implemented as a UserControl.

代码隐藏

 public sealed partial class CommonPromptView {
    private const int CloseViewTimeIntervalInMilliseconds = 120000;
    private DispatcherTimer timer;

    public static readonly DependencyProperty CommonPromptBorderStyleProperty = DependencyProperty.Register(
        "CommonPromptBorderStyle", typeof (Style), typeof (CommonPromptView), new PropertyMetadata(default(Style)));

    public Style CommonPromptBorderStyle {
        get { return (Style) GetValue(CommonPromptBorderStyleProperty); }
        set { SetValue(CommonPromptBorderStyleProperty, value); }
    }

    public static readonly DependencyProperty CommonPromptHeaderStyleProperty = DependencyProperty.Register(
        "CommonPromptHeaderStyle", typeof (Style), typeof (CommonPromptView), new PropertyMetadata(default(Style)));

    public Style CommonPromptHeaderStyle {
        get { return (Style) GetValue(CommonPromptHeaderStyleProperty); }
        set { SetValue(CommonPromptHeaderStyleProperty, value); }
    }

    public static readonly DependencyProperty CommonPromptMessageStyleProperty = DependencyProperty.Register(
        "CommonPromptMessageStyle", typeof (Style), typeof (CommonPromptView), new PropertyMetadata(default(Style)));

    public Style CommonPromptMessageStyle {
        get { return (Style) GetValue(CommonPromptMessageStyleProperty); }
        set { SetValue(CommonPromptMessageStyleProperty, value); }
    }

    public static readonly DependencyProperty CommonPromptSpitterStyleProperty = DependencyProperty.Register(
        "CommonPromptSpitterStyle", typeof (Style), typeof (CommonPromptView), new PropertyMetadata(default(Style)));

    public Style CommonPromptSpitterStyle {
        get { return (Style) GetValue(CommonPromptSpitterStyleProperty); }
        set { SetValue(CommonPromptSpitterStyleProperty, value); }
    }

    public static readonly DependencyProperty CommonPromptButtonStyleProperty = DependencyProperty.Register(
        "CommonPromptButtonStyle", typeof (Style), typeof (CommonPromptView), new PropertyMetadata(default(Style)));

    public Style CommonPromptButtonStyle {
        get { return (Style) GetValue(CommonPromptButtonStyleProperty); }
        set { SetValue(CommonPromptButtonStyleProperty, value); }
    }

    [SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public CommonPromptView(object header = null, string message = "Вы действительно хотите продолжить?",
        Visibility headerVisibility = Visibility.Collapsed,
        MessageBoxIconWPF iconType = MessageBoxIconWPF.Question,
        object affirmButtonContent = null, object cancelButtonContent = null,
        Visibility cancelButtonVisibility = Visibility.Visible, Visibility affirmButtonVisibility = Visibility.Visible) {
        InitializeComponent();
        Header.Content = header ?? string.Empty;
        if (header == null)
            HeaderSplitter.Visibility = Visibility.Collapsed;
        Message.Content = message;

        Ok.Content = affirmButtonContent ?? "ОК";
        Cancel.Content = cancelButtonContent ?? "Отмена";

        Cancel.Visibility = cancelButtonVisibility;
        Header.Visibility = headerVisibility;
        Ok.Visibility = affirmButtonVisibility;

        BitmapImage icon = new BitmapImage();
        icon.BeginInit();
        icon.UriSource = new Uri(GetIconPath(iconType));
        //new Uri("pack://application:,,,/ApplicationName;component/Resources/logo.png");
        icon.EndInit();

        Icon.Source = icon;

        SetTimer();
    }

    private static string GetIconPath(MessageBoxIconWPF icon) {
        const string uri = "pack://application:,,,/Microtech.WPF.Common;component/";
        string iconName;
        switch (icon) {
            case MessageBoxIconWPF.Error:
                iconName = "CustomDialogStop";
                break;
            case MessageBoxIconWPF.Information:
                iconName = "CustomDialogInformation";
                break;
            case MessageBoxIconWPF.Question:
                iconName = "CustomDialogQuestion";
                break;
            case MessageBoxIconWPF.Warning:
                iconName = "CustomDialogWarning";
                break;
            default:
                throw new ArgumentException("There were no such an image");
        }
        return uri + string.Format("Images/{0}.{1}", iconName, "png");
    }

    public CommonPromptView(string content, Visibility cancelButtonVisibility = Visibility.Visible)
        : this(message: content, cancelButtonVisibility: cancelButtonVisibility) {
    }

    private void SetTimer() {
        TimeSpan timerInterval = TimeSpan.FromMilliseconds(CloseViewTimeIntervalInMilliseconds);
        timer = new DispatcherTimer(timerInterval, DispatcherPriority.ApplicationIdle,
            (obj, e) => Cancel_Click(null, null),
            Dispatcher.CurrentDispatcher);
        timer.Start();
    }

    public CommonPromptView() {
        InitializeComponent();
    }

    public static bool PromptOnUserAgreement(string header, string message, string okText = "Да",
        string cancelText = "Нет") {
        return new CommonPromptView(header,
            message, Visibility.Visible, MessageBoxIconWPF.Information, okText, cancelText).ShowDialog()
            .GetValueOrDefault();
    }

    public static void PromptOnWarning(string header, string message) {
        new CommonPromptView(header, message, headerVisibility: Visibility.Visible, iconType: MessageBoxIconWPF.Warning,
            cancelButtonVisibility: Visibility.Collapsed).ShowDialog();
    }

    public static void PromptOnError(string header, string message) {
        new CommonPromptView(header, message, headerVisibility: Visibility.Visible, iconType: MessageBoxIconWPF.Error,
            cancelButtonVisibility: Visibility.Collapsed).ShowDialog();
    }

    public static void PromptOnSuccess(string header, string message) {
        new CommonPromptView(header, message, headerVisibility: Visibility.Visible,
            iconType: MessageBoxIconWPF.Information,
            cancelButtonVisibility: Visibility.Collapsed).ShowDialog();
    }

    private void Ok_Click(object sender, RoutedEventArgs e) {
        StopTimer();
        TryCloseTheWindow(true);            
    }

    private void Cancel_Click(object sender, RoutedEventArgs e) {
        StopTimer();
        TryCloseTheWindow(false);
    }

    private void TryCloseTheWindow(bool dialogResult) {
        Window parentwin = GetWindow(this);
        if (parentwin != null) {
            try {
                parentwin.DialogResult = dialogResult;
            } catch (InvalidOperationException) {

            }
            parentwin.Close();
        }
    }

    private void StopTimer() {
        if (timer != null) {
            timer.Stop();
            timer = null;
        }
    }
}

XAML

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"                  
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="Microtech.WPF.Common.CommonPromptView"
             Background="Transparent" 
             DataContext="{Binding RelativeSource={RelativeSource Self}}">

<UserControl.Resources>
    <Style x:Key="DefaultViewStyle" TargetType="Window">
        <Setter Property="ResizeMode" Value="NoResize" />
        <Setter Property="ShowInTaskbar" Value="False" />
        <Setter Property="WindowStyle" Value="None" />
        <Setter Property="WindowState" Value="Normal" />
        <Setter Property="SizeToContent" Value="WidthAndHeight" />
        <Setter Property="Topmost" Value="True" />
        <Setter Property="Cursor" Value="Arrow" />
    </Style>

    <Style x:Key="DefaultHeaderStyle" TargetType="Label">
        <Setter Property="Margin" Value="10,5,5,5"/>
        <Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="FontSize" Value="20" />
        <Setter Property="FontWeight" Value="Bold" />
    </Style>

    <Style x:Key="DefaultBorderStyle" TargetType="Border">
        <Setter Property="Background" Value="#ADAAAD"/>
        <Setter Property="BorderBrush" Value="Black" />
        <Setter Property="Padding" Value="10" />
        <Setter Property="BorderThickness" Value="3"/>
        <Setter Property="CornerRadius" Value="10"/>          
    </Style>

    <Style x:Key="DefaultMessageStyle" TargetType="Label">
        <Setter Property="Margin" Value="10"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="FontFamily" Value="Verdana"/>
        <Setter Property="FontWeight" Value="Normal"/>
    </Style>

    <Style x:Key="DefaultSplitterStyle" TargetType="GridSplitter">
        <Setter Property="HorizontalAlignment" Value="Stretch" />
        <Setter Property="VerticalAlignment" Value="Bottom" />
        <Setter Property="BorderThickness" Value="0.65" />
        <Setter Property="BorderBrush" Value="Black" />
        <Setter Property="IsEnabled" Value="False" />
    </Style>

    <Style x:Key="FStandartButton" TargetType="{x:Type Button}">
        <Setter Property="Background" Value="{x:Null}" />
        <Setter Property="BorderBrush" Value="#00000000" />
        <Setter Property="Foreground" Value="White" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="Height" Value="Auto" />
        <Setter Property="MinHeight" Value="55" />
        <Setter Property="Width" Value="420" />
        <Setter Property="Margin" Value="5" />
        <Setter Property="Padding" Value="10" />
        <Setter Property="FontSize" Value="22" />
        <Setter Property="FontWeight" Value="Bold" />
        <Setter Property="FocusVisualStyle" Value="{x:Null}" />

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Border x:Name="border" BorderBrush="#FF000000" BorderThickness="1,1,1,1" CornerRadius="4,4,4,4">
                        <Border.Background>
                            <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                                <GradientStop Offset="0" Color="#8C8A8C" />
                                <GradientStop Offset="1" Color="#636163" />
                            </LinearGradientBrush>
                        </Border.Background>
                        <ContentPresenter Name="ContentContainer" 
                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                          RecognizesAccessKey="True"
                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsPressed" Value="True">
                            <Setter TargetName="border" Property="Background" Value="#CC000000" />
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Foreground" Value="Gray" />
                        </Trigger>

                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="DefaultButtonStyle" TargetType="Button" BasedOn="{StaticResource FStandartButton}">
        <Setter Property="FontFamily" Value="Verdana"/>
        <Setter Property="FontSize" Value="14"/>
        <Setter Property="Margin" Value="6"/>
    </Style>
</UserControl.Resources>

<Border Style="{Binding CommonPromptBorderStyle, TargetNullValue={StaticResource DefaultBorderStyle}}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Label x:Name="Header"
               Style="{Binding CommonPromptHeaderStyle, TargetNullValue={StaticResource DefaultHeaderStyle}}" />
        <GridSplitter x:Name="HeaderSplitter" Grid.Row="0" 
                      Style="{Binding CommonPromptSpitterStyle, TargetNullValue={StaticResource DefaultSplitterStyle}}"
                      />

        <StackPanel Grid.Row="1" Margin="5,10,5,0" Orientation="Horizontal">
            <Image x:Name="Icon" Width="32" Height="32" Margin="5" 
                   HorizontalAlignment="Left"
                   VerticalAlignment="Center" />
            <Label x:Name="Message" 
                   Style="{Binding CommonPromptMessageStyle, 
                           TargetNullValue={StaticResource DefaultMessageStyle}}" />
        </StackPanel>

        <StackPanel Grid.Row="2" HorizontalAlignment="Center" Orientation="Horizontal">
            <Button x:Name="Ok" 
                    Style="{Binding CommonPromptButtonStyle, TargetNullValue={StaticResource DefaultButtonStyle}}"  
                    Click="Ok_Click" />
            <Button x:Name="Cancel" 
                    Style="{Binding CommonPromptButtonStyle, TargetNullValue={StaticResource DefaultButtonStyle}}"  
                    IsDefault="True" Click="Cancel_Click" />
        </StackPanel>
    </Grid>
</Border>

推荐答案

我觉得在你的情况下你需要看DataTemplate的方向,使动态内容.我做了几个例子来说明这一点.这些例子的一般含义:

I think in your case you need to look in the direction of DataTemplate, to make the dynamic content. I made a few examples that show this. The general meaning of this examples:

给定两个按钮,一个给用户,一个给管理员.如果选择User,则内容显示给用户,如果选择Admin,则显示给管理员.

Given two buttons, one for the user and one for the administrator. If you choose the User, the content is displayed to the user, if the Admin, then for administrator.

显然,这不是最现实的例子,但这只是展示内容动态选择的一种方式.对于您,您将确定替换内容的条件.

Clearly, this is not the most realistic example, but it's just a way to show the dynamic selection of content. For you, you will determine the condition of replacement content.

示例 A

此示例演示了根据输入值动态替换DataTemplates.如果我们从样式模式的角度考虑,它与抽象工厂非常相似,其中不是类 - DataTemplate,并且工厂方法是一个动态的 DataTemplate 选择器.示例完全适用于 MVVM 模式.下面是一个例子:

This example demonstrates the dynamic replacing DataTemplates, depending on the input values​​. If we think in terms of style patterns, it is very similar to the abstract factory, where instead of classes - DataTemplate, and factory method is a dynamic DataTemplate selector. Example is fully suitable for MVVM pattern. Below is an example:

MainWindow.xaml

<Grid>
    <ContentControl Name="MainView"
                    ContentTemplate="{StaticResource MainView}">

        <ViewModels:MainViewModel />
    </ContentControl>
</Grid>

MainView.xaml

它是 ResourceDictionary 中的一个 DataTemplate.有两个模板:UserTemplate 和AdminTemplate.一份给用户,一份给管理员.在ContentControl 的样式中定义了ContentTemplateSelector,以及将被条件安装的模板集合.在 DynamicContentControl 的属性 Content 中设置内容字符串,可以是:UserAdmin.

It's a DataTemplate in ResourceDictionary. There are two templates: UserTemplate and AdminTemplate. One for the user and one for the administrator. In the style of ContentControl defined ContentTemplateSelector, and a collection of templates that will be installed by the condition. In property Content for DynamicContentControl is set content string that can be: User or Admin.

<DataTemplateSelectors:DynamicTemplateSelector x:Key="MyTemplateSelector" />

<DataTemplate x:Key="UserTemplate">
    <StackPanel>
        <TextBlock Text="Content for user"
                   FontSize="20"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center" />

        <Button Content="Yes" />
        <Button Content="No" />
    </StackPanel>
</DataTemplate>

<DataTemplate x:Key="AdminTemplate">
    <StackPanel>
        <TextBlock Text="Content for admin"
                   FontSize="20"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center" />

        <TextBox Text="Whom banned?" />
        <Button Content="Ban" />
        <Button Content="AntiBan" />
    </StackPanel>
</DataTemplate>

<Style x:Key="DynamicContentStyle" TargetType="{x:Type ContentControl}">
    <Setter Property="ContentTemplateSelector" Value="{StaticResource MyTemplateSelector}" />
    <Setter Property="Width" Value="200" />
    <Setter Property="Height" Value="200" />

    <Setter Property="DataTemplateSelectors:DynamicTemplateSelector.Templates">
        <Setter.Value>
            <DataTemplateSelectors:TemplateCollection>
                <DataTemplateSelectors:Template Value="User" 
                                                DataTemplate="{StaticResource UserTemplate}" />

                <DataTemplateSelectors:Template Value="Admin" 
                                                DataTemplate="{StaticResource AdminTemplate}" />
            </DataTemplateSelectors:TemplateCollection>
        </Setter.Value>
    </Setter>
</Style>

<DataTemplate x:Key="MainView" DataType="{x:Type ViewModels:MainViewModel}">
    <Grid>
        <Button Name="UserButton"
                Content="Are you user?"
                Width="100"
                Height="30"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Command="{Binding UserButtonCommand}" />

        <Button Name="AdminButton"
                Content="Are you admin?"
                Width="100"
                Height="30"
                HorizontalAlignment="Right"
                VerticalAlignment="Top"
                Command="{Binding AdminButtonCommand}" />

        <ContentControl Name="DynamicContent"                            
                        Style="{StaticResource DynamicContentStyle}"
                        Content="{Binding Path=MainModel.ContentType,
                                          Mode=TwoWay,
                                          UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</DataTemplate>

MainViewModel.cs

此处在命令中设置内容类型.

Here in commands set the content type.

public class MainViewModel
{
    #region MainModel

    private MainModel _mainModel = null;

    public MainModel MainModel
    {
        get
        {
            return _mainModel;
        }

        set
        {
            _mainModel = value;
        }
    }

    #endregion

    #region UserButton Command

    private ICommand _userButtonCommand = null;

    public ICommand UserButtonCommand
    {
        get
        {
            if (_userButtonCommand == null)
            {
                _userButtonCommand = new RelayCommand(param => this.UserButton(), null);
            }

            return _userButtonCommand;
        }
    }

    private void UserButton() 
    {
        MainModel.ContentType = "User";
    }

    #endregion

    #region AdminButton Command

    private ICommand _adminButtonCommand = null;

    public ICommand AdminButtonCommand
    {
        get
        {
            if (_adminButtonCommand == null)
            {
                _adminButtonCommand = new RelayCommand(param => this.AdminButton(), null);
            }

            return _adminButtonCommand;
        }
    }

    private void AdminButton()
    {
        MainModel.ContentType = "Admin";
    }

    #endregion

    public MainViewModel() 
    {
        MainModel = new MainModel();
    }
}

MainModel.cs

public class MainModel : NotificationObject
{
    private string _contentType = "";

    public string ContentType
    {
        get
        {
            return _contentType;
        }

        set
        {
            _contentType = value;
            NotifyPropertyChanged("ContentType");
        }
    }
}

DynamicTemplateSelector

从 CodeProject 中提取,几乎没有返工:

Taken and little reworked from CodeProject:

public class DynamicTemplateSelector : DataTemplateSelector
{
    #region Templates Dependency Property

    public static readonly DependencyProperty TemplatesProperty =
        DependencyProperty.RegisterAttached("Templates", typeof(TemplateCollection), typeof(DataTemplateSelector),
        new FrameworkPropertyMetadata(new TemplateCollection(), FrameworkPropertyMetadataOptions.Inherits));

    public static TemplateCollection GetTemplates(UIElement element)
    {
        return (TemplateCollection)element.GetValue(TemplatesProperty);
    }

    public static void SetTemplates(UIElement element, TemplateCollection collection)
    {
        element.SetValue(TemplatesProperty, collection);
    }

    #endregion

    #region SelectTemplate

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        string myStringItem = (string)item;

        if (!(container is UIElement))
        {
            return base.SelectTemplate(item, container);
        }

        TemplateCollection templates = GetTemplates(container as UIElement);

        if (templates == null || templates.Count == 0)
        {
            base.SelectTemplate(item, container);
        }

        foreach (var template in templates)
        {
            if (myStringItem.Equals(template.Value.ToString()))
            {
                return template.DataTemplate;
            }
        }

        return base.SelectTemplate(item, container);
    }

    #endregion
}

#region TemplateCollection

public class TemplateCollection : List<Template>
{

}

#endregion

#region Template Dependency Object

public class Template : DependencyObject
{
    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(Template));

    public static readonly DependencyProperty DataTemplateProperty =
       DependencyProperty.Register("DataTemplate", typeof(DataTemplate), typeof(Template));

    public string Value
    { get { return (string)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } }

    public DataTemplate DataTemplate
    { get { return (DataTemplate)GetValue(DataTemplateProperty); } set { SetValue(DataTemplateProperty, value); } }
}

#endregion

用户结果

管理员结果

这种方式的注意事项

优点:

  • 完全独立于不同的视图

缺点:

  • 需要为每个条件创建单独的数据模板 (View),在某些情况下为 ViewModel.

结论:

这种方法适用于完全不同的视图,如果表示没有太大的不同,你看第二个例子.

This method is suitable for completely different views, if the representations are not much different, you see a second example.

示例 B

本例使用一个DataTemplate,数据取自模型,默认所有控件都隐藏(Visibility.Collapsed),中的所有动作>View 通过 DataTriggers 执行.示例完全适用于 MVVM 模式.

This example uses a one DataTemplate, the data is taken from the model, by default, all controls are hidden (Visibility.Collapsed), all actions in View are performed via DataTriggers. Example is fully suitable for MVVM pattern.

MainWindow.xaml

<Grid>
    <ContentControl Name="MainView"
                    ContentTemplate="{StaticResource MainView}">

        <ViewModels:MainViewModel />
    </ContentControl>
</Grid>

MainView.xaml

<DataTemplate x:Key="MainView" DataType="{x:Type ViewModels:MainViewModel}">
    <Grid>
        <Button Name="UserButton"
                Content="Are you user?"
                Width="100"
                Height="30"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Command="{Binding UserButtonCommand}" />

        <Button Name="AdminButton"
                Content="Are you admin?"
                Width="100"
                Height="30"
                HorizontalAlignment="Right"
                VerticalAlignment="Top"
                Command="{Binding AdminButtonCommand}" />

        <StackPanel Name="MainViewPanel"
                    Tag="{Binding Path=MainModel.ContentType,
                                  Mode=TwoWay, 
                                  UpdateSourceTrigger=PropertyChanged}">

            <TextBlock Name="TitleTextBlock"
                       Text="{Binding Path=MainModel.TitleText,
                                      Mode=TwoWay, 
                                      UpdateSourceTrigger=PropertyChanged}"
                       FontSize="20"
                       HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       Visibility="Collapsed" />

            <TextBox Name="BannedTextBlock"
                     Text="{Binding Path=MainModel.BannedName,
                                    Mode=TwoWay, 
                                    UpdateSourceTrigger=PropertyChanged}"
                     Visibility="Collapsed" />

            <Button Name="YesButton" 
                    Content="{Binding Path=MainModel.ContentYesButton,
                                      Mode=TwoWay, 
                                      UpdateSourceTrigger=PropertyChanged}" 
                    Visibility="Collapsed" />

            <Button Name="NoButton" 
                    Content="{Binding Path=MainModel.ContentNoButton,
                                      Mode=TwoWay, 
                                      UpdateSourceTrigger=PropertyChanged}" 
                    Visibility="Collapsed" />
        </StackPanel>
    </Grid>

    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding ElementName=MainViewPanel, Path=Tag}" Value="User">
            <Setter TargetName="TitleTextBlock" Property="Visibility" Value="Visible" />
            <Setter TargetName="YesButton" Property="Visibility" Value="Visible" />
        </DataTrigger>

        <DataTrigger Binding="{Binding ElementName=MainViewPanel, Path=Tag}" Value="Admin">
            <Setter TargetName="TitleTextBlock" Property="Visibility" Value="Visible" />
            <Setter TargetName="BannedTextBlock" Property="Visibility" Value="Visible" />
            <Setter TargetName="YesButton" Property="Visibility" Value="Visible" />
            <Setter TargetName="NoButton" Property="Visibility" Value="Visible" />
        </DataTrigger>
    </DataTemplate.Triggers>
</DataTemplate>

MainViewModel.cs

public class MainViewModel
{
    #region MainModel

    private MainModel _mainModel = null;

    public MainModel MainModel
    {
        get
        {
            return _mainModel;
        }

        set
        {
            _mainModel = value;
        }
    }

    #endregion

    #region UserButton Command

    private ICommand _userButtonCommand = null;

    public ICommand UserButtonCommand
    {
        get
        {
            if (_userButtonCommand == null)
            {
                _userButtonCommand = new RelayCommand(param => this.UserButton(), null);
            }

            return _userButtonCommand;
        }
    }

    private void UserButton() 
    {
        MainModel.ContentType = "User";
        MainModel.TitleText = "Hello User!";
        MainModel.ContentYesButton = "Yes";
        MainModel.ContentNoButton = "No";
    }

    #endregion

    #region AdminButton Command

    private ICommand _adminButtonCommand = null;

    public ICommand AdminButtonCommand
    {
        get
        {
            if (_adminButtonCommand == null)
            {
                _adminButtonCommand = new RelayCommand(param => this.AdminButton(), null);
            }

            return _adminButtonCommand;
        }
    }

    private void AdminButton()
    {
        MainModel.ContentType = "Admin";
        MainModel.TitleText = "Hello Admin!";
        MainModel.BannedName = "John Doe";
        MainModel.ContentYesButton = "Ban";
        MainModel.ContentNoButton = "AntiBan";
    }

    #endregion

    public MainViewModel() 
    {
        MainModel = new MainModel();
    }
}

MainModel.cs

public class MainModel : NotificationObject
{
    #region ContentType

    private string _contentType = "";

    public string ContentType
    {
        get
        {
            return _contentType;
        }

        set
        {
            _contentType = value;
            NotifyPropertyChanged("ContentType");
        }
    }

    #endregion

    #region TitleText

    private string _titleText = "";

    public string TitleText
    {
        get
        {
            return _titleText;
        }

        set
        {
            _titleText = value;
            NotifyPropertyChanged("TitleText");
        }
    }

    #endregion

    #region BannedName

    private string _bannedName = "";

    public string BannedName
    {
        get
        {
            return _bannedName;
        }

        set
        {
            _bannedName = value;
            NotifyPropertyChanged("BannedName");
        }
    }

    #endregion

    #region ContentYesButton

    private string _contentYesButton = "";

    public string ContentYesButton
    {
        get
        {
            return _contentYesButton;
        }

        set
        {
            _contentYesButton = value;
            NotifyPropertyChanged("ContentYesButton");
        }
    }

    #endregion

    #region ContentNoButton

    private string _contentNoButton = "";

    public string ContentNoButton
    {
        get
        {
            return _contentNoButton;
        }

        set
        {
            _contentNoButton = value;
            NotifyPropertyChanged("ContentNoButton");
        }
    }

    #endregion
}

用户结果

管理员结果

这种方式的注意事项

优点:

  • 只有一个数据模板

缺点:

  • 如果表现形式彼此非常不同,则在View中需要操作很多控件和数据.
  • if the representations are very different from each other, in the View the need to manipulate a lot of controls and data.

结论:

这种方法适用于Views,它们之间的差别不是很大,不同值的数量也不会太大.

This method is suitable for Views, which is not very different from each other, and the number of different values is not too large.

这两个示例都可在此 链接.

Both examples are available at this link.

这篇关于制作(创建)可重用的动态视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆