gpt4 book ai didi

c# - 控件模板 Storyboard ,在同一模板内的其他控件中设置值

转载 作者:行者123 更新时间:2023-11-30 17:00:55 25 4
gpt4 key购买 nike

有人要求我围绕现有的 DateTimePicker 控件创建一个 hack。通常,日期/时间选择器有一个精美的日历图像,然后是它旁边的文本框,用于显示实际日期。用户可以单击图像并弹出日历,选择后,日期会刷新到文本框区域。

我遇到的问题是其他设计师不喜欢日历图形,只想要一个普通的文本框控件,但如果用户双击,打开弹出式日历,获取日期并刷新它。多亏了在 S/O 上找到的其他帮助,我非常接近这一点。

所以,描述我的控件模板,并保持简单(非自定义控件,除非我需要根据建议)。控件模板基于文本框控件。我们有一个带有文本框 PART_ContentHost 的边框,然后是一个标准日历控件的弹出窗口。

对于控件模板触发器,我有一个链接到 ScrollViewer(文本框输入区域)的 MouseDoubleClick 事件。如果触发,则将弹出窗口的 IsOpen 设置为 true 并公开日历。这很好用。

现在,完成它。如果用户从日历中选择一个日期,下一个触发器将关闭弹出窗口(IsOpen 设置为 false)。这也行。

我的问题。我还希望在选择时采用所选日期并将其 ToString() 日期表示形式放入 ScrollViewer.Content (x:Name="PART_ContentHost)。

<ControlTemplate TargetType="{x:Type TextBox}" x:Key="CTTextBox" >
<StackPanel>
<Border x:Name="targetBorder"
BorderBrush="{TemplateBinding BorderBrush}"
SnapsToDevicePixels="true">

<ScrollViewer x:Name="PART_ContentHost"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
Foreground="{TemplateBinding Foreground}" />
</Border>
<Popup PlacementTarget="{Binding ElementName=PART_ContentHost}" x:Name="PopCal">
<Calendar x:Name="ActualCalendar"/>
</Popup>
</StackPanel>

<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="ScrollViewer.MouseDoubleClick" SourceName="PART_ContentHost">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames
Storyboard.TargetName="PopCal"
Storyboard.TargetProperty="(Popup.IsOpen)">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>

<EventTrigger RoutedEvent="Calendar.SelectedDatesChanged" SourceName="ActualCalendar">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames
Storyboard.TargetName="PopCal"
Storyboard.TargetProperty="(Popup.IsOpen)">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>


WHAT WOULD I PUT HERE to have the selected date of the popup calendar
inserted into the content of the PART_ContentHost...
<Storyboard>
<BooleanAnimationUsingKeyFrames
Storyboard.TargetName="PART_ContentHost"
Storyboard.TargetProperty="(Content)">
<DiscreteBooleanKeyFrame KeyTime="00:00:00" Value=" ????? "/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>

</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>

<Style TargetType="{x:Type TextBox}" x:Key="STextBox" >
<!--<Setter Property="OverridesDefaultStyle" Value="True"/>-->
<Setter Property="FontFamily" Value="Arial" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Height" Value="20" />
<Setter Property="Width" Value="100" />
<Setter Property="VerticalContentAlignment" Value="Bottom" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="HorizontalAlignment" Value="Left" />
<!-- Padding is Left, Top, Right, Bottom -->
<Setter Property="Padding" Value="2,0,0,2" />
<Setter Property="Margin" Value="0,0,0,0" />

<Setter Property="Visibility" Value="Visible" />
<Setter Property="IsEnabled" Value="True" />

<Setter Property="CharacterCasing" Value="Upper" />
<Setter Property="BorderThickness" Value="1" />

<Setter Property="BorderBrush" Value="Black" />
<Setter Property="Background" Value="White" />
<Setter Property="Foreground" Value="Black" />

<Setter Property="Template" Value="{StaticResource CTTextBox}" />
</Style>

最佳答案

我确信可以通过多种方式解决问题,但在这些情况下我通常会执行附加行为。但是while情况不太正常,因为这里实现了一个模板控件。无论如何,我认为附加行为适合这种情况,在你的位置我会这样做。

附加行为是非常强大和方便的解决方案,完全满足 MVVM 模式,也可以在 Blend 中使用(具有预定义的接口(interface))。附加行为 - 是一个附加属性,它有一个事件处理程序来更改此属性,并且所有逻辑都在此处理程序中实现。

在开始意识到行为之前,我会考虑对您的模板所做的一些更改。

我有点不明白你为什么要使用PART_ContentHost ScrollViewer 控件,也许会有几个日期需要滚动显示。在 WPF 中,显示内容需要两个控件:

  1. 内容展示器
  2. 内容控制

这是他们的主要目标。 first lightest 通常用在模板中,但它不支持事件,我们需要协调工作,所以我选择了ContentControl。在小东西上为模板添加绑定(bind)属性,设置为Popup:

AllowsTransparency="True"
VerticalOffset="4"
HorizontalOffset="-5"

为了更好的可视化。现在转到行为示例。

XAML

<Window.Resources>
<ControlTemplate x:Key="CTTextBox" TargetType="{x:Type TextBox}">
<StackPanel AttachedBehaviors:SelectDateBehavior.IsEnabled="True"> <!-- Here is determined behaviour -->
<Border x:Name="targetBorder"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
TextBlock.Foreground="{TemplateBinding Foreground}"
SnapsToDevicePixels="True">

<ContentControl x:Name="ContentHost"
Content="{TemplateBinding Text}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="4,0,0,0" />
</Border>

<Popup x:Name="PopCal"
AllowsTransparency="True"
VerticalOffset="4"
HorizontalOffset="-5"
PlacementTarget="{Binding ElementName=ContentHost}">

<Calendar x:Name="ActualCalendar" />
</Popup>
</StackPanel>
</ControlTemplate>

<Style TargetType="{x:Type TextBox}" x:Key="STextBox">
<Setter Property="FontFamily" Value="Arial" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Height" Value="25" />
<Setter Property="Width" Value="100" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="CharacterCasing" Value="Upper" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="Gray" />
<Setter Property="Background" Value="AliceBlue" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="Template" Value="{StaticResource CTTextBox}" />
</Style>
</Window.Resources>

<Grid>
<TextBox Style="{StaticResource STextBox}"
Text="Select date" />
</Grid>

附加行为

public class SelectDateBehavior
{
#region IsEnabled Dependency Property

public static readonly DependencyProperty IsEnabledProperty;

public static void SetIsEnabled(DependencyObject DepObject, bool value)
{
DepObject.SetValue(IsEnabledProperty, value);
}

public static bool GetIsEnabled(DependencyObject DepObject)
{
return (bool)DepObject.GetValue(IsEnabledProperty);
}

static SelectDateBehavior()
{
IsEnabledProperty = DependencyProperty.RegisterAttached("IsEnabled",
typeof(bool),
typeof(SelectDateBehavior),
new UIPropertyMetadata(false, IsEnabledChanged));
}

#endregion

#region IsEnabledChanged Handler

private static void IsEnabledChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
Panel panel = sender as Panel;

if (panel != null)
{
if (e.NewValue is bool && ((bool)e.NewValue) == true)
{
panel.Loaded += new RoutedEventHandler(panelLoaded);
}
else
{
panel.Loaded -= new RoutedEventHandler(panelLoaded);
}
}
}

#endregion

#region Panel Loaded Handler

private static void panelLoaded(object sender, RoutedEventArgs e)
{
Panel panel = sender as Panel;
Border border = panel.FindName("targetBorder") as Border;
ContentControl contentHost = border.FindName("ContentHost") as ContentControl;
Popup popup = panel.FindName("PopCal") as Popup;

if (popup != null)
{
Calendar calendar = popup.FindName("ActualCalendar") as Calendar;
calendar.SelectedDatesChanged += new EventHandler<SelectionChangedEventArgs>(calendarSelectedDatesChanged);
}

if (contentHost != null)
{
contentHost.MouseDoubleClick += new MouseButtonEventHandler(contentHostMouseDoubleClick);
}
}

#endregion

#region ContentHost MouseDoubleClick Handler

private static void contentHostMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
ContentControl contentHost = sender as ContentControl;
Border border = contentHost.Parent as Border;
Panel panel = border.Parent as Panel;
Popup popup = panel.FindName("PopCal") as Popup;

if (popup != null)
{
popup.IsOpen = true;
}
}

#endregion

#region Calendar SelectedDatesChanged Handler

private static void calendarSelectedDatesChanged(object sender, SelectionChangedEventArgs e)
{
Calendar calendar = sender as Calendar;
Popup popup = calendar.Parent as Popup;
Panel panel = popup.Parent as Panel;
Border border = panel.FindName("targetBorder") as Border;
ContentControl contentHost = border.FindName("ContentHost") as ContentControl;

if (popup != null)
{
contentHost.Content = calendar.SelectedDate;
popup.IsOpen = false;
}
}

#endregion
}

输出

enter image description here

设置当前日期在这里进行:

private static void calendarSelectedDatesChanged(object sender, SelectionChangedEventArgs e) 
{
// Skipped a few lines of code
if (popup != null)
{
contentHost.Content = calendar.SelectedDate;
popup.IsOpen = false;
}
}

一些注意事项

让我提请注意一些功能。首先,我们必须摆脱 EventTrigger Storyboard,因为在 WPF 动画中设置最高优先级值 ,这意味着如果一旦我们在动画中设置值 IsOpen,从其他来源访问(代码等)是不可能的。所以我把所有的触发器/事件放在一边。

其次,解决方案与模板和控件的结构密切相关。这意味着如果必须更改模板的结构,则必须更改行为(可能不多)。

This example is available here.

关于c# - 控件模板 Storyboard ,在同一模板内的其他控件中设置值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21606679/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com