[英]WPF Lookless Control Events
我有以下課程:
public class LooklessControl : Control
{
public List<int> IntList { get; private set; }
public int CurrentInt { get; private set; }
private int _index = 0;
static LooklessControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(LooklessControl), new FrameworkPropertyMetadata(typeof(LooklessControl)));
}
public LooklessControl()
{
IntList = new List<int>();
for (int i = 0; i < 10; i++)
{
IntList.Add(i);
}
CurrentInt = IntList[_index];
}
public static readonly RoutedCommand NextItemCommand =
new RoutedCommand("NextItemCommand", typeof(LooklessControl));
private void ExecutedNextItemCommand(object sender, ExecutedRoutedEventArgs e)
{
NextItemHandler();
}
private void CanExecuteNextItemCommand(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
public static readonly RoutedCommand PrevItemCommand =
new RoutedCommand("PrevItemCommand", typeof(LooklessControl));
private void ExecutedPrevItemCommand(ExecutedRoutedEventArgs e)
{
PrevItemHandler();
}
private void CanExecutePrevItemCommand(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
public static readonly RoutedEvent NextItemEvent =
EventManager.RegisterRoutedEvent("NextItemEvent", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(LooklessControl));
public event RoutedEventHandler NextItem
{
add { AddHandler(NextItemEvent, value); }
remove { RemoveHandler(NextItemEvent, value); }
}
private void RaiseNextItemEvent()
{
RoutedEventArgs args = new RoutedEventArgs(LooklessControl.NextItemEvent);
RaiseEvent(args);
}
public static readonly RoutedEvent PrevItemEvent =
EventManager.RegisterRoutedEvent("PrevItemEvent", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(LooklessControl));
public event RoutedEventHandler PrevItem
{
add { AddHandler(PrevItemEvent, value); }
remove { RemoveHandler(PrevItemEvent, value); }
}
private void RaisePrevItemEvent()
{
RoutedEventArgs args = new RoutedEventArgs(LooklessControl.PrevItemEvent);
RaiseEvent(args);
}
private void NextItemHandler()
{
_index++;
if (_index == IntList.Count)
{
_index = 0;
}
CurrentInt = IntList[_index];
RaiseNextItemEvent();
}
private void PrevItemHandler()
{
_index--;
if (_index == 0)
{
_index = IntList.Count - 1;
}
CurrentInt = IntList[_index];
RaisePrevItemEvent();
}
}
該類在 Generic.xaml 中有一個默認樣式,如下所示:
<Style x:Key="{x:Type local:LooklessControl}" TargetType="{x:Type local:LooklessControl}">
<Setter Property="Height" Value="200"/>
<Setter Property="Width" Value="90"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:LooklessControl}">
<Border BorderBrush="Black" BorderThickness="1" Padding="2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Grid.Row="0" Fill="LightGray"/>
<Rectangle Grid.Row="1" Fill="Gainsboro"/>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="10"/>
</Grid.ColumnDefinitions>
<Path Grid.Column="0" x:Name="pathLeftArrow" Data="M0,0.5 L1,1 1,0Z" Width="6" Height="14" Stretch="Fill"
HorizontalAlignment="Center" Fill="SlateBlue"/>
<TextBlock Grid.Column="1" Name="textBlock"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=CurrentInt}"
HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Junction" FontSize="13"/>
<Path Grid.Column="2" x:Name="pathRightArrow" Data="M0,0 L1,0.5 0,1Z" Width="6" Height="14" Stretch="Fill"
HorizontalAlignment="Center" Fill="SlateBlue"/>
</Grid>
<ListBox Grid.Row="1" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Background="Transparent"
ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IntList}"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我如何做到這一點,以便當用戶單擊 pathLeftArrow 時它會觸發 LooklessControl.PrevItemCommand,或者他們單擊 pathRightArrow 並觸發 LooklessControl.NextItemCommand,或者他們單擊 ListBox 中的一個項目並且 LooklessControl 會收到新選擇的項目的通知?
換句話說,如果不將 x:Class 添加到 Generic.xaml 的頂部並因此為其創建代碼隱藏文件(我假設您不想這樣做),您如何處理 xaml 中不存在的元素的事件沒有 Command 屬性(除了 Button 之外的所有東西)?
LooklessControl 是否應該擁有自己的 XAML 文件(很像您在創建新的 UserControl 時獲得的文件),Generic.xaml 是否應該將其作為 MergedDictionar 作為其默認模板引入? 或者有沒有其他公認的方法來做我想做的事情?
回答你的最后一個問題:不。 無外觀控件不應該需要任何已知的 XAML。 這就是lookless的意思。
您在這里有幾個選項,但我建議您使用一個基本為空的控件模板將元素包裝在 Buttons 中:
<ControlTemplate x:Key="contentOnlyButton" TargetType="{x:Type Button}">
<ContentPresenter />
</ControlTemplate>
...
<Button Grid.Column="0" Template="{StaticResource contentOnlyButton}"
Command="{x:Static local:LooklessControl.PrevItemCommand}">
<Path x:Name="pathLeftArrow" Data="M0,0.5 L1,1 1,0Z" Width="6" Height="14"
Stretch="Fill" HorizontalAlignment="Center" Fill="SlateBlue"/>
</Button>
您的另一個選擇(我會說這可能不是您在點擊時執行命令時應該做的,但可能適用於其他情況),是在 OnApplyTemplate 的模板中查找命名部分,並連接事件.
public override void OnApplyTemplate()
{
var prevElement = this.GetTemplateChild("PART_PathLeftArrow") as UIElement;
if (prevElement != null)
prevElement.MouseDown += (o, e) => PrevItemHandler();
...
}
這樣做需要注意的一件事是模板不需要定義您正在尋找的部分,因此您需要優雅地檢查這種情況。 在這里拋出NullReferenceExceptions
將使重新設計控件樣式成為意外刪除所需元素的設計人員/開發人員的痛苦。 您還需要遵循使用 PART_ 語法命名所需元素並使用TemplatePart
屬性裝飾類的標准做法。
[TemplatePart(Name = "PART_PathLeftArrow", Type = typeof(UIElement))]
[TemplatePart(Name = "PART_PathRightArrow", Type = typeof(UIElement))]
...
public class LooklessControl : Control
編輯:為了讓 Button 響應點擊,您需要將 CommandBindings 設置為您已經定義的函數。 您可以將其作為類命令綁定來執行,如下所示:
static LooklessControl()
{
CommandManager.RegisterClassCommandBinding(
typeof(LooklessControl),
new CommandBinding(NextItemCommand, ExecutedNextItemCommand, CanExecuteNextItemCommand));
CommandManager.RegisterClassCommandBinding(
typeof(LooklessControl),
new CommandBinding(PrevItemCommand, ExecutedPrevItemCommand, CanExecutePrevItemCommand));
}
進行類命令綁定的原因是,如果將其添加到控件的 CommandBindings 集合中,則使用您的控件的人可能會無意中刪除它們。 還要記住更新您的命令處理方法以具有靜態語義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.