使用HandyControl的TextBox封装一个选择路径的控件:
1.自定义一个SelectPathTextBox类继承自HandyControl中的TextBox,并添加一个选择路径按钮的依赖属性
提示:CommonOpenFileDialog 需要通过nuget安装 WindowsAPICodePack-Shell 才能使用
public class SelectPathTextBox : TextBox
{
public static readonly DependencyProperty SelectPathCommandProperty = DependencyProperty.Register("SelectPathCommand", typeof(ICommand), typeof(SelectPathTextBox));
private ICommand _selectPathCommand;
public ICommand SelectPathCommand
{
get { return (ICommand)GetValue(SelectPathCommandProperty); }
set { SetValue(SelectPathCommandProperty, value); }
}
public SelectPathTextBox()
{
SelectPathCommand = new DelegateCommand<object>((object obj) =>
{
string fullFileName = this.Text;
CommonOpenFileDialog dialog = new CommonOpenFileDialog();
dialog.InitialDirectory = fullFileName;
dialog.IsFolderPicker = true;
if (dialog.ShowDialog(GetTopWindow()) != CommonFileDialogResult.Ok)
return;
fullFileName = dialog.FileName;
SetCurrentValue(TextProperty, fullFileName);
});
}
//获取Top窗口
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
public static System.Windows.Window GetTopWindow()
{
var hwnd = GetActiveWindow();
if (hwnd == IntPtr.Zero)
return Application.Current.MainWindow;
return GetWindowFromHwnd(hwnd);
}
private static System.Windows.Window GetWindowFromHwnd(IntPtr hwnd)
{
var fromHwnd = HwndSource.FromHwnd(hwnd);
if (fromHwnd != null)
return (System.Windows.Window)fromHwnd.RootVisual;
return null;
}
}
2.添加样式:
提示:TargetType需要指向上面自定义的类。Template中的Button 绑定到自定义类中的依赖属性
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:control="clr-namespace:XXXXXXXXXX.Control"
<Style x:Key="CustomTextBoxBaseStyle" TargetType="control:SelectPathTextBox">
<Setter Property="MinHeight" Value="{StaticResource DefaultControlHeight}" />
<Setter Property="Background" Value="{DynamicResource RegionBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrush}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CaretBrush" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="hc:BorderElement.CornerRadius" Value="{StaticResource DefaultCornerRadius}" />
<Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="Padding" Value="{StaticResource DefaultInputPadding}" />
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="control:SelectPathTextBox">
<Grid MinHeight="{Binding Path=(hc:InfoElement.MinContentHeight),RelativeSource={RelativeSource TemplatedParent}}" Height="{Binding Path=(hc:InfoElement.ContentHeight),RelativeSource={RelativeSource TemplatedParent}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Path=(hc:InfoElement.TitleWidth),RelativeSource={RelativeSource TemplatedParent}}"/>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<DockPanel LastChildFill="True" Visibility="{Binding Path=(hc:InfoElement.Title),RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource String2VisibilityConverter}}" VerticalAlignment="{Binding Path=(hc:TitleElement.VerticalAlignment),RelativeSource={RelativeSource TemplatedParent}}" Margin="0,7,6,7">
<TextBlock DockPanel.Dock="Left" hc:TextBlockAttach.AutoTooltip="True" TextWrapping="NoWrap" TextTrimming="CharacterEllipsis" Text="{Binding Path=(hc:InfoElement.Title),RelativeSource={RelativeSource TemplatedParent}}"/>
<ContentPresenter DockPanel.Dock="Left" TextElement.Foreground="{DynamicResource DangerBrush}" Margin="4,0,0,0" Content="{Binding Path=(hc:InfoElement.Symbol),RelativeSource={RelativeSource TemplatedParent}}" Visibility="{Binding Path=(hc:InfoElement.Necessary),RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource Boolean2VisibilityConverter}}"/>
</DockPanel>
<Border x:Name="border" Grid.Column="1" Grid.ColumnSpan="2" CornerRadius="{Binding Path=(hc:BorderElement.CornerRadius),RelativeSource={RelativeSource TemplatedParent}}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True"/>
<TextBlock x:Name="Placeholder" Padding="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}" Grid.Column="1" Visibility="{TemplateBinding Text,Converter={StaticResource String2VisibilityReConverter}}" HorizontalAlignment="Stretch" Style="{StaticResource TextBlockDefaultThiLight}" Text="{Binding Path=(hc:InfoElement.Placeholder),RelativeSource={RelativeSource TemplatedParent}}"/>
<ScrollViewer Padding="{TemplateBinding Padding}" Margin="-1,1" Grid.Column="1" x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
<Button Grid.Column="2" HorizontalAlignment="Right" Command="{TemplateBinding SelectPathCommand}" Style="{StaticResource ButtonInfo}" hc:IconElement.Geometry="M912 208H427.872l-50.368-94.176A63.936 63.936 0 0 0 321.056 80H112c-35.296 0-64 28.704-64 64v736c0 35.296 28.704 64 64 64h800c35.296 0 64-28.704 64-64v-608c0-35.296-28.704-64-64-64z m-800-64h209.056l68.448 128H912v97.984c-0.416 0-0.8-0.128-1.216-0.128H113.248c-0.416 0-0.8 0.128-1.248 0.128V144z m0 736v-96l1.248-350.144 798.752 1.216V784h0.064v96H112z" Background="#059491"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.4" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource SecondaryBorderBrush}" />
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource PrimaryBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
3.使用:
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:control="clr-namespace:XXXXXXX.Control"
<control:SelectPathTextBox hc:InfoElement.TitleWidth="120"
hc:InfoElement.Placeholder="路径"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.Title="路径"
hc:InfoElement.Necessary="True"
hc:InfoElement.Symbol="●"
Text="{Binding Path, Mode=TwoWay}"
Style="{StaticResource CustomTextBoxBaseStyle}"
VerticalAlignment="Center"/>