条件 XAML (WPF)

发布于 2024-10-15 23:09:48 字数 3149 浏览 3 评论 0原文

我正在尝试创建一个用户控件,根据用户在依赖属性中设置的模式,将用户控件更改为一个 TextBlock 和另一个 TextBlock 或一个 TextBlock 和一个 TextBox。我知道依赖属性正在获取信息,但是当我尝试设置正确的模板时,问题就出现了。由于某种原因,模板无法正确呈现。

XAML:

<UserControl
    x:Class="BookOrganizer.FlipBox"
    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:my="clr-namespace:BookOrganizer"
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel Orientation="Horizontal" Height="Auto" Width="Auto" >
        <StackPanel.Resources>
            <ContentControl x:Key="Box">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" />
                    <TextBox Text="{Binding Path=Text}" Height="Auto" Width="Auto" />
                </StackPanel>
            </ContentControl>
            <ContentControl x:Key="Block" Height="Auto" Width="Auto">
                <StackPanel Orientation="Horizontal" Height="Auto" Width="Auto">
                    <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" />
                    <TextBlock Text="{Binding Path=Text}" Height="Auto" Width="Auto"/>
                </StackPanel>
            </ContentControl>
        </StackPanel.Resources>
        <ContentControl Template="{Binding Path=BoxMode}" />
    </StackPanel>
</UserControl>

代码隐藏:

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

namespace BookOrganizer
{
    /// <summary>
    /// Interaction logic for FlipBox.xaml
    /// </summary>
    public partial class FlipBox : UserControl
    {
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
        "Title", typeof(String), typeof(FlipBox), new PropertyMetadata("nothing"));

        public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
        "Text", typeof(String), typeof(FlipBox), new PropertyMetadata("nothing"));

        public static readonly DependencyProperty BoxModeProperty = DependencyProperty.Register(
        "BoxMode", typeof(String), typeof(FlipBox), new PropertyMetadata("Box"));

        public FlipBox()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        public String Title
        {
            get { return (String)this.GetValue(TitleProperty); }
            set { this.SetValue(TitleProperty, value); }
        }

        public String Text
        {
            get { return (String)this.GetValue(TextProperty); }
            set { this.SetValue(TextProperty, value); }
        }

        public String BoxMode
        {
            get { return (String)this.GetValue(BoxModeProperty); }
            set { this.SetValue(BoxModeProperty, value); }
        }

    }
}

提前致谢。

I am trying to create a User Control that, depending on the mode the user sets in the Dependency Property, changes the User Control to either a TextBlock and another TextBlock or a TextBlock and a TextBox. I know the dependency properties are getting the information, but the problem arises when I try to set the correct template. For some reason, the template does not render correctly.

XAML:

<UserControl
    x:Class="BookOrganizer.FlipBox"
    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:my="clr-namespace:BookOrganizer"
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel Orientation="Horizontal" Height="Auto" Width="Auto" >
        <StackPanel.Resources>
            <ContentControl x:Key="Box">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" />
                    <TextBox Text="{Binding Path=Text}" Height="Auto" Width="Auto" />
                </StackPanel>
            </ContentControl>
            <ContentControl x:Key="Block" Height="Auto" Width="Auto">
                <StackPanel Orientation="Horizontal" Height="Auto" Width="Auto">
                    <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" />
                    <TextBlock Text="{Binding Path=Text}" Height="Auto" Width="Auto"/>
                </StackPanel>
            </ContentControl>
        </StackPanel.Resources>
        <ContentControl Template="{Binding Path=BoxMode}" />
    </StackPanel>
</UserControl>

Code Behind:

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

namespace BookOrganizer
{
    /// <summary>
    /// Interaction logic for FlipBox.xaml
    /// </summary>
    public partial class FlipBox : UserControl
    {
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
        "Title", typeof(String), typeof(FlipBox), new PropertyMetadata("nothing"));

        public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
        "Text", typeof(String), typeof(FlipBox), new PropertyMetadata("nothing"));

        public static readonly DependencyProperty BoxModeProperty = DependencyProperty.Register(
        "BoxMode", typeof(String), typeof(FlipBox), new PropertyMetadata("Box"));

        public FlipBox()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        public String Title
        {
            get { return (String)this.GetValue(TitleProperty); }
            set { this.SetValue(TitleProperty, value); }
        }

        public String Text
        {
            get { return (String)this.GetValue(TextProperty); }
            set { this.SetValue(TextProperty, value); }
        }

        public String BoxMode
        {
            get { return (String)this.GetValue(BoxModeProperty); }
            set { this.SetValue(BoxModeProperty, value); }
        }

    }
}

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

堇年纸鸢 2024-10-22 23:09:48

您可以使用触发器来设置模板。将 UserControl 中的 StackPanel 替换为...

   <StackPanel Orientation="Horizontal" Height="Auto" Width="Auto" >
      <ContentControl>
         <ContentControl.Style>
            <Style TargetType="{x:Type ContentControl}">
               <Style.Triggers>
                  <DataTrigger Binding="{Binding Path=BoxMode}" Value="Box">
                     <Setter Property="Template">
                        <Setter.Value>
                           <ControlTemplate>
                              <StackPanel Orientation="Horizontal" Height="Auto" Width="Auto">
                                 <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" />
                                 <TextBlock Text="{Binding Path=Text}" Height="Auto" Width="Auto"/>
                              </StackPanel>
                           </ControlTemplate>
                        </Setter.Value>
                     </Setter>
                  </DataTrigger>
                  <DataTrigger Binding="{Binding Path=BoxMode}" Value="Block">
                     <Setter Property="Template">
                        <Setter.Value>
                           <ControlTemplate>
                              <StackPanel Orientation="Horizontal">
                                 <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" />
                                 <TextBox Text="{Binding Path=Text}" Height="Auto" Width="Auto" />
                              </StackPanel>
                           </ControlTemplate>
                        </Setter.Value>
                     </Setter>
                  </DataTrigger>
               </Style.Triggers>
            </Style>
         </ContentControl.Style>
      </ContentControl>
   </StackPanel>

You can use triggers to set the template. Replace the StackPanel in your UserControl with this...

   <StackPanel Orientation="Horizontal" Height="Auto" Width="Auto" >
      <ContentControl>
         <ContentControl.Style>
            <Style TargetType="{x:Type ContentControl}">
               <Style.Triggers>
                  <DataTrigger Binding="{Binding Path=BoxMode}" Value="Box">
                     <Setter Property="Template">
                        <Setter.Value>
                           <ControlTemplate>
                              <StackPanel Orientation="Horizontal" Height="Auto" Width="Auto">
                                 <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" />
                                 <TextBlock Text="{Binding Path=Text}" Height="Auto" Width="Auto"/>
                              </StackPanel>
                           </ControlTemplate>
                        </Setter.Value>
                     </Setter>
                  </DataTrigger>
                  <DataTrigger Binding="{Binding Path=BoxMode}" Value="Block">
                     <Setter Property="Template">
                        <Setter.Value>
                           <ControlTemplate>
                              <StackPanel Orientation="Horizontal">
                                 <TextBlock Text="{Binding Path=Title}" Height="Auto" Width="Auto" />
                                 <TextBox Text="{Binding Path=Text}" Height="Auto" Width="Auto" />
                              </StackPanel>
                           </ControlTemplate>
                        </Setter.Value>
                     </Setter>
                  </DataTrigger>
               </Style.Triggers>
            </Style>
         </ContentControl.Style>
      </ContentControl>
   </StackPanel>
北陌 2024-10-22 23:09:48

以下是如何创建条件控件的示例:

public class ConditionalControl : ContentControl
{
    static ConditionalControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof (ConditionalControl), new FrameworkPropertyMetadata(typeof (ConditionalControl)));
    }

    #region Condition DP

    public bool Condition
    {
        get { return (bool) GetValue(ConditionProperty); }
        set { SetValue(ConditionProperty, value); }
    }

    public static readonly DependencyProperty ConditionProperty =
        DependencyProperty.Register("Condition", typeof (bool), typeof (ConditionalControl), new UIPropertyMetadata(false));

    #endregion

    #region TrueTemplate DP

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

    public static readonly DependencyProperty TrueTemplateProperty =
        DependencyProperty.Register("TrueTemplate", typeof (DataTemplate), typeof (ConditionalControl), new UIPropertyMetadata(null));

    #endregion

    #region FalseTemplate DP

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

    public static readonly DependencyProperty FalseTemplateProperty =
        DependencyProperty.Register("FalseTemplate", typeof (DataTemplate), typeof (ConditionalControl), new UIPropertyMetadata(null));

    #endregion
}

以下是您需要放入项目中的 Themes/Generic.xaml 中的样式:

<Style TargetType="{x:Type Controls:ConditionalControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Controls:ConditionalControl}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">

                    <Grid>
                        <ContentPresenter x:Name="FalseContentPresenter"
                                          Content="{TemplateBinding DataContext}"
                                          ContentTemplate="{TemplateBinding FalseTemplate}" />
                    </Grid>

                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

    <Style.Triggers>
        <Trigger Property="Condition"
                 Value="True">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Controls:ConditionalControl}">
                        <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">

                            <Grid>
                                <ContentPresenter x:Name="TrueContentPresenter"
                                                  Content="{TemplateBinding DataContext}"
                                                  ContentTemplate="{TemplateBinding TrueTemplate}" />
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Trigger>
    </Style.Triggers>
</Style>

Here is an example of how you can create a conditional control:

public class ConditionalControl : ContentControl
{
    static ConditionalControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof (ConditionalControl), new FrameworkPropertyMetadata(typeof (ConditionalControl)));
    }

    #region Condition DP

    public bool Condition
    {
        get { return (bool) GetValue(ConditionProperty); }
        set { SetValue(ConditionProperty, value); }
    }

    public static readonly DependencyProperty ConditionProperty =
        DependencyProperty.Register("Condition", typeof (bool), typeof (ConditionalControl), new UIPropertyMetadata(false));

    #endregion

    #region TrueTemplate DP

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

    public static readonly DependencyProperty TrueTemplateProperty =
        DependencyProperty.Register("TrueTemplate", typeof (DataTemplate), typeof (ConditionalControl), new UIPropertyMetadata(null));

    #endregion

    #region FalseTemplate DP

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

    public static readonly DependencyProperty FalseTemplateProperty =
        DependencyProperty.Register("FalseTemplate", typeof (DataTemplate), typeof (ConditionalControl), new UIPropertyMetadata(null));

    #endregion
}

Here is it's style that you need to put in Themes/Generic.xaml in you project:

<Style TargetType="{x:Type Controls:ConditionalControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Controls:ConditionalControl}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">

                    <Grid>
                        <ContentPresenter x:Name="FalseContentPresenter"
                                          Content="{TemplateBinding DataContext}"
                                          ContentTemplate="{TemplateBinding FalseTemplate}" />
                    </Grid>

                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

    <Style.Triggers>
        <Trigger Property="Condition"
                 Value="True">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Controls:ConditionalControl}">
                        <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">

                            <Grid>
                                <ContentPresenter x:Name="TrueContentPresenter"
                                                  Content="{TemplateBinding DataContext}"
                                                  ContentTemplate="{TemplateBinding TrueTemplate}" />
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Trigger>
    </Style.Triggers>
</Style>
掀纱窥君容 2024-10-22 23:09:48

您可能需要一个 IValueConverter 来将该 string 更改为预期的 ControlTemplate。当作为裸字符串传递时,它不会查找资源键。一种不同的解决方案是使用 Style 来改变可见性:

<StackPanel Orientation="Horizontal">
     <TextBlock Text="{Binding Title}" />
     <TextBox Text="{Binding Text}">
          <TextBox.Style>
              <Style TargetType="TextBox">
                  <Setter Property="Visibility" Value="Collapsed" />
                  <Style.Triggers>
                      <DataTrigger Binding="{Binding BoxMode}" Value="Box">
                          <Setter Property="Visibility" Value="Visible" />
                      </DataTrigger>
                  </Style.Triggers>
              </Style>
          </TextBox.Style>
     </TextBox>
     <TextBlock Text="{Binding Text}">
          <TextBlock.Style>
              <Style TargetType="TextBlock">
                  <Setter Property="Visibility" Value="Visible" />
                  <Style.Triggers>
                      <DataTrigger Binding="{Binding BoxMode}" Value="Box">
                          <Setter Property="Visibility" Value="Collapsed" />
                      </DataTrigger>
                  </Style.Triggers>
              </Style>
          </TextBlock.Style>
     </TextBlock>
</StackPanel>

You will likely need an IValueConverter to change that string to a ControlTemplate that is expected. It will not do the lookup of the resource key when passed as a bare string. A different solution would be to use a Style to alter the visibility:

<StackPanel Orientation="Horizontal">
     <TextBlock Text="{Binding Title}" />
     <TextBox Text="{Binding Text}">
          <TextBox.Style>
              <Style TargetType="TextBox">
                  <Setter Property="Visibility" Value="Collapsed" />
                  <Style.Triggers>
                      <DataTrigger Binding="{Binding BoxMode}" Value="Box">
                          <Setter Property="Visibility" Value="Visible" />
                      </DataTrigger>
                  </Style.Triggers>
              </Style>
          </TextBox.Style>
     </TextBox>
     <TextBlock Text="{Binding Text}">
          <TextBlock.Style>
              <Style TargetType="TextBlock">
                  <Setter Property="Visibility" Value="Visible" />
                  <Style.Triggers>
                      <DataTrigger Binding="{Binding BoxMode}" Value="Box">
                          <Setter Property="Visibility" Value="Collapsed" />
                      </DataTrigger>
                  </Style.Triggers>
              </Style>
          </TextBlock.Style>
     </TextBlock>
</StackPanel>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文