首次提交
This commit is contained in:
22
WpfAppTest/App.config
Normal file
22
WpfAppTest/App.config
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.1.0" newVersion="6.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.4.0" newVersion="4.0.4.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
245
WpfAppTest/App.xaml
Normal file
245
WpfAppTest/App.xaml
Normal file
@@ -0,0 +1,245 @@
|
||||
<Application
|
||||
x:Class="WpfAppTest.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:Controls="clr-namespace:WpfAppTest.Controls"
|
||||
xmlns:converters="clr-namespace:WpfAppTest.Converter"
|
||||
xmlns:local="clr-namespace:WpfAppTest"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
StartupUri="ModernWindow.xaml">
|
||||
<Application.Resources>
|
||||
<!-- <Color x:Key="RevitBgColor">#F0F0F0</Color>
|
||||
<Color x:Key="RevitBorderBrush">#D0D0D0</Color>
|
||||
<Color x:Key="RevitSelectedBgColor">#0078D7</Color>
|
||||
<Color x:Key="RevitSelectedFgColor">White</Color>
|
||||
<Color x:Key="RevitHoverBgColor">#ADD8E6</Color>
|
||||
<Color x:Key="RevitDropdownBgColor">White</Color>
|
||||
<Color x:Key="RevitDefaultFgColor">Black</Color>
|
||||
<Color x:Key="RevitDisabledFgColor">#A0A0A0</Color>
|
||||
<SolidColorBrush x:Key="RevitBgBrush" Color="{StaticResource RevitBgColor}"/>
|
||||
<SolidColorBrush x:Key="RevitBorderBrush" Color="{StaticResource RevitBorderBrush}"/>
|
||||
<SolidColorBrush x:Key="RevitSelectedBgBrush" Color="{StaticResource RevitSelectedBgColor}"/>
|
||||
<SolidColorBrush x:Key="RevitSelectedFgBrush" Color="{StaticResource RevitSelectedFgColor}"/>
|
||||
<SolidColorBrush x:Key="RevitHoverBgBrush" Color="{StaticResource RevitHoverBgColor}"/>
|
||||
<SolidColorBrush x:Key="RevitDropdownBgBrush" Color="{StaticResource RevitDropdownBgColor}"/>
|
||||
<SolidColorBrush x:Key="RevitDefaultFgBrush" Color="{StaticResource RevitDefaultFgColor}"/>
|
||||
<SolidColorBrush x:Key="RevitDisabledFgBrush" Color="{StaticResource RevitDisabledFgColor}"/>
|
||||
|
||||
<DropShadowEffect x:Key="ComboBoxDropShadowEffect"
|
||||
ShadowDepth="2"
|
||||
Direction="270"
|
||||
Color="#000000"
|
||||
Opacity="0.2"
|
||||
BlurRadius="5"/>
|
||||
|
||||
<Style TargetType="{x:Type ComboBoxItem}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
<Setter Property="Padding" Value="6,4,6,4"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource RevitDefaultFgBrush}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
|
||||
<Border x:Name="Bd"
|
||||
Background="{TemplateBinding Background}"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
SnapsToDevicePixels="True">
|
||||
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsHighlighted" Value="True">
|
||||
<Setter TargetName="Bd" Property="Background" Value="{StaticResource RevitHoverBgBrush}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource RevitDefaultFgBrush}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter TargetName="Bd" Property="Background" Value="{StaticResource RevitSelectedBgBrush}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource RevitSelectedFgBrush}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Foreground" Value="{StaticResource RevitDisabledFgBrush}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
|
||||
<Grid>
|
||||
<Border x:Name="Border"
|
||||
Background="{StaticResource RevitBgBrush}" BorderBrush="{StaticResource RevitBorderBrush}" BorderThickness="1" CornerRadius="0"/>
|
||||
|
||||
<Path x:Name="Arrow"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,1,0,0"
|
||||
Fill="{StaticResource RevitDefaultFgBrush}"
|
||||
Data="M0,0 L4,4 L8,0 Z" />
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="Border" Property="Background" Value="{StaticResource RevitHoverBgBrush}"/>
|
||||
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource RevitHoverBgBrush}"/>
|
||||
<Setter TargetName="Arrow" Property="Fill" Value="{StaticResource RevitDefaultFgBrush}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter TargetName="Border" Property="Background" Value="{StaticResource RevitHoverBgBrush}"/>
|
||||
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource RevitHoverBgBrush}"/>
|
||||
<Setter TargetName="Arrow" Property="Fill" Value="{StaticResource RevitDefaultFgBrush}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="Border" Property="Background" Value="{StaticResource RevitBgBrush}"/>
|
||||
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource RevitBorderBrush}"/>
|
||||
<Setter TargetName="Arrow" Property="Fill" Value="{StaticResource RevitDisabledFgBrush}"/>
|
||||
<Setter TargetName="Border" Property="Opacity" Value="0.6"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="MyRevitComboBoxStyle" TargetType="{x:Type ComboBox}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
<Setter Property="OverridesDefaultStyle" Value="True"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource RevitDefaultFgBrush}"/>
|
||||
<Setter Property="Background" Value="{StaticResource RevitBgBrush}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource RevitBorderBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="Padding" Value="6,2,0,2"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ComboBox}">
|
||||
<Grid x:Name="templateRoot">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="20"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal"/>
|
||||
<VisualState x:Name="MouseOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Bg" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<SolidColorBrush Color="{StaticResource RevitHoverBgColor}"/>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Bg" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<SolidColorBrush Color="{StaticResource RevitHoverBgColor}"/>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="templateRoot" Storyboard.TargetProperty="Opacity">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<sys:Double>0.6</sys:Double>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="FocusStates">
|
||||
<VisualState x:Name="Focused">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Bg" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<SolidColorBrush Color="{StaticResource RevitHoverBgColor}"/>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Unfocused"/>
|
||||
<VisualState x:Name="FocusedDropDown"/>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="ValidationStates">
|
||||
<VisualState x:Name="Valid"/>
|
||||
<VisualState x:Name="InvalidUnfocused"/>
|
||||
<VisualState x:Name="InvalidFocused"/>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
|
||||
<Border x:Name="Bg"
|
||||
Grid.ColumnSpan="2"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="0"/>
|
||||
|
||||
<ContentPresenter x:Name="ContentSite"
|
||||
Grid.Column="0" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
IsHitTestVisible="False"
|
||||
Content="{TemplateBinding SelectionBoxItem}"
|
||||
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
|
||||
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
|
||||
<ToggleButton x:Name="ToggleButton"
|
||||
Grid.Column="1" Template="{StaticResource ComboBoxToggleButton}"
|
||||
Focusable="False"
|
||||
ClickMode="Press"
|
||||
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
|
||||
|
||||
<TextBox x:Name="PART_EditableTextBox"
|
||||
Grid.Column="0" Style="{x:Null}"
|
||||
Template="{x:Null}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
Visibility="Hidden"
|
||||
Focusable="True"
|
||||
IsReadOnly="{TemplateBinding IsReadOnly}"/>
|
||||
|
||||
<Popup x:Name="PART_Popup"
|
||||
AllowsTransparency="True"
|
||||
Placement="Bottom"
|
||||
IsOpen="{TemplateBinding IsDropDownOpen}"
|
||||
PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}"
|
||||
Margin="0"
|
||||
Grid.ColumnSpan="2">
|
||||
<Border x:Name="DropDownBorder"
|
||||
BorderBrush="{StaticResource RevitBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Background="{StaticResource RevitDropdownBgBrush}"
|
||||
MaxHeight="{TemplateBinding MaxDropDownHeight}"
|
||||
MinWidth="{TemplateBinding ActualWidth}"
|
||||
Effect="{StaticResource ComboBoxDropShadowEffect}">
|
||||
<ScrollViewer Margin="0" SnapsToDevicePixels="True"
|
||||
VerticalScrollBarVisibility="Hidden"
|
||||
HorizontalScrollBarVisibility="Hidden">
|
||||
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Contained"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Popup>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsEditable" Value="True">
|
||||
<Setter Property="IsTabStop" Value="False"/>
|
||||
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
|
||||
<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>-->
|
||||
<!--<ResourceDictionary Source="/Generic.xaml" />-->
|
||||
<ResourceDictionary Source="/ModernStyles.xaml" />
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
17
WpfAppTest/App.xaml.cs
Normal file
17
WpfAppTest/App.xaml.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace WpfAppTest
|
||||
{
|
||||
/// <summary>
|
||||
/// App.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
||||
237
WpfAppTest/ElementHelper.cs
Normal file
237
WpfAppTest/ElementHelper.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shell;
|
||||
|
||||
namespace ModernWpf.Controls
|
||||
{
|
||||
// ==========================================
|
||||
// 1. 附加属性帮助类 (新增 Prefix)
|
||||
// ==========================================
|
||||
public class ElementHelper : DependencyObject
|
||||
{
|
||||
// ... 原有的属性保持不变 (Watermark, Icon, CornerRadius, Header) ...
|
||||
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached("Watermark", typeof(string), typeof(ElementHelper), new PropertyMetadata(""));
|
||||
public static void SetWatermark(DependencyObject element, string value) => element.SetValue(WatermarkProperty, value);
|
||||
public static string GetWatermark(DependencyObject element) => (string)element.GetValue(WatermarkProperty);
|
||||
|
||||
public static readonly DependencyProperty IconProperty = DependencyProperty.RegisterAttached("Icon", typeof(Geometry), typeof(ElementHelper), new PropertyMetadata(null));
|
||||
public static void SetIcon(DependencyObject element, Geometry value) => element.SetValue(IconProperty, value);
|
||||
public static Geometry GetIcon(DependencyObject element) => (Geometry)element.GetValue(IconProperty);
|
||||
|
||||
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached("CornerRadius", typeof(CornerRadius), typeof(ElementHelper), new PropertyMetadata(new CornerRadius(4)));
|
||||
public static void SetCornerRadius(DependencyObject element, CornerRadius value) => element.SetValue(CornerRadiusProperty, value);
|
||||
public static CornerRadius GetCornerRadius(DependencyObject element) => (CornerRadius)element.GetValue(CornerRadiusProperty);
|
||||
|
||||
public static readonly DependencyProperty HeaderProperty = DependencyProperty.RegisterAttached("Header", typeof(string), typeof(ElementHelper), new PropertyMetadata(""));
|
||||
public static void SetHeader(DependencyObject element, string value) => element.SetValue(HeaderProperty, value);
|
||||
public static string GetHeader(DependencyObject element) => (string)element.GetValue(HeaderProperty);
|
||||
|
||||
// === 新增 Prefix 属性 (支持文字或UI元素) ===
|
||||
public static readonly DependencyProperty PrefixProperty = DependencyProperty.RegisterAttached("Prefix", typeof(object), typeof(ElementHelper), new PropertyMetadata(null));
|
||||
public static void SetPrefix(DependencyObject element, object value) => element.SetValue(PrefixProperty, value);
|
||||
public static object GetPrefix(DependencyObject element) => element.GetValue(PrefixProperty);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 2. ModernWindow (保持不变)
|
||||
// ==========================================
|
||||
public class ModernWindow : Window
|
||||
{
|
||||
static ModernWindow()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(ModernWindow), new FrameworkPropertyMetadata(typeof(ModernWindow)));
|
||||
}
|
||||
|
||||
public ModernWindow()
|
||||
{
|
||||
var chrome = new WindowChrome
|
||||
{
|
||||
CaptionHeight = 32,
|
||||
ResizeBorderThickness = new Thickness(4),
|
||||
// 让系统边框可见,从而触发 Win11 原生圆角和阴影
|
||||
GlassFrameThickness = new Thickness(1),
|
||||
UseAeroCaptionButtons = false
|
||||
};
|
||||
WindowChrome.SetWindowChrome(this, chrome);
|
||||
|
||||
CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, (s, e) => SystemCommands.CloseWindow(this)));
|
||||
CommandBindings.Add(new CommandBinding(SystemCommands.MaximizeWindowCommand, (s, e) => SystemCommands.MaximizeWindow(this)));
|
||||
CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand, (s, e) => SystemCommands.MinimizeWindow(this)));
|
||||
CommandBindings.Add(new CommandBinding(SystemCommands.RestoreWindowCommand, (s, e) => SystemCommands.RestoreWindow(this)));
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
if (GetTemplateChild("PART_TitleBar") is Border titleBar)
|
||||
{
|
||||
titleBar.MouseLeftButtonDown += (s, e) =>
|
||||
{
|
||||
if (e.ClickCount == 2)
|
||||
{
|
||||
if (ResizeMode != ResizeMode.NoResize)
|
||||
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
|
||||
}
|
||||
else
|
||||
{
|
||||
DragMove();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SearchableComboBox : ComboBox
|
||||
{
|
||||
private TextBox _editableTextBox;
|
||||
private bool _isInternalOperation;
|
||||
|
||||
static SearchableComboBox()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(SearchableComboBox), new FrameworkPropertyMetadata(typeof(SearchableComboBox)));
|
||||
}
|
||||
|
||||
public SearchableComboBox()
|
||||
{
|
||||
IsEditable = true;
|
||||
IsTextSearchEnabled = false;
|
||||
StaysOpenOnEdit = true;
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
_editableTextBox = GetTemplateChild("PART_EditableTextBox") as TextBox;
|
||||
if (_editableTextBox != null)
|
||||
{
|
||||
_editableTextBox.TextChanged += OnEditableTextBoxTextChanged;
|
||||
// 点击时全选
|
||||
_editableTextBox.GotFocus += (s, e) => _editableTextBox.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
|
||||
{
|
||||
if (_isInternalOperation) return;
|
||||
|
||||
_isInternalOperation = true;
|
||||
base.OnSelectionChanged(e);
|
||||
|
||||
// 重点 1:选中项改变后,必须彻底清空过滤器,否则下次打开下拉框只剩下一项
|
||||
this.Items.Filter = null;
|
||||
_isInternalOperation = false;
|
||||
}
|
||||
|
||||
private void OnEditableTextBoxTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (_isInternalOperation) return;
|
||||
|
||||
string searchText = _editableTextBox.Text;
|
||||
string selectedText = GetItemDisplayText(SelectedItem);
|
||||
|
||||
// 重点 2:断开锁定逻辑
|
||||
// 如果文本框的内容和当前选中项的文本不一致,说明用户正在打字替换内容
|
||||
if (SelectedItem != null && searchText != selectedText)
|
||||
{
|
||||
_isInternalOperation = true;
|
||||
SelectedItem = null; // 必须将 SelectedItem 设为 null,否则 WPF 会强行还原文本
|
||||
_isInternalOperation = false;
|
||||
}
|
||||
|
||||
// 重点 3:执行过滤
|
||||
this.Items.Filter = item =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(searchText)) return true;
|
||||
|
||||
string itemText = GetItemDisplayText(item);
|
||||
|
||||
// 只要包含关键字就显示(忽略大小写)
|
||||
return itemText.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
};
|
||||
|
||||
// 自动打开下拉框
|
||||
if (!IsDropDownOpen && _editableTextBox.IsFocused && !string.IsNullOrEmpty(searchText))
|
||||
{
|
||||
IsDropDownOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetItemDisplayText(object item)
|
||||
{
|
||||
if (item == null) return string.Empty;
|
||||
if (item is ComboBoxItem cbi) return cbi.Content?.ToString() ?? string.Empty;
|
||||
|
||||
// 兼容 DisplayMemberPath 或 TextSearch.TextPath
|
||||
string path = DisplayMemberPath;
|
||||
if (string.IsNullOrEmpty(path)) path = TextSearch.GetTextPath(this);
|
||||
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
var prop = item.GetType().GetProperty(path);
|
||||
if (prop != null) return prop.GetValue(item)?.ToString() ?? string.Empty;
|
||||
}
|
||||
return item.ToString();
|
||||
}
|
||||
}
|
||||
public class ModernPasswordBox : Control
|
||||
{
|
||||
static ModernPasswordBox()
|
||||
{
|
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(ModernPasswordBox), new FrameworkPropertyMetadata(typeof(ModernPasswordBox)));
|
||||
}
|
||||
|
||||
public string Password
|
||||
{
|
||||
get => (string)GetValue(PasswordProperty);
|
||||
set => SetValue(PasswordProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register("Password", typeof(string), typeof(ModernPasswordBox), new PropertyMetadata(string.Empty));
|
||||
|
||||
// 辅助属性:标记是否为空,用于 XAML 控制水印显隐
|
||||
public bool IsEmpty
|
||||
{
|
||||
get => (bool)GetValue(IsEmptyProperty);
|
||||
private set => SetValue(IsEmptyProperty, value);
|
||||
}
|
||||
public static readonly DependencyProperty IsEmptyProperty = DependencyProperty.Register("IsEmpty", typeof(bool), typeof(ModernPasswordBox), new PropertyMetadata(true));
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
var pb = GetTemplateChild("PART_PasswordBox") as PasswordBox;
|
||||
var tb = GetTemplateChild("PART_TextBox") as TextBox;
|
||||
var btn = GetTemplateChild("PART_ToggleBtn") as ToggleButton;
|
||||
|
||||
if (pb != null && tb != null && btn != null)
|
||||
{
|
||||
pb.PasswordChanged += (s, e) =>
|
||||
{
|
||||
if (pb.Visibility == Visibility.Visible)
|
||||
{
|
||||
Password = pb.Password;
|
||||
IsEmpty = string.IsNullOrEmpty(pb.Password);
|
||||
}
|
||||
};
|
||||
|
||||
tb.TextChanged += (s, e) =>
|
||||
{
|
||||
if (tb.Visibility == Visibility.Visible)
|
||||
{
|
||||
Password = tb.Text;
|
||||
IsEmpty = string.IsNullOrEmpty(tb.Text);
|
||||
}
|
||||
};
|
||||
|
||||
btn.Checked += (s, e) => { tb.Text = pb.Password; tb.Visibility = Visibility.Visible; pb.Visibility = Visibility.Collapsed; };
|
||||
btn.Unchecked += (s, e) => { pb.Password = tb.Text; pb.Visibility = Visibility.Visible; tb.Visibility = Visibility.Collapsed; };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
WpfAppTest/Fonts/HanYiCuSongJian.ttf
Normal file
BIN
WpfAppTest/Fonts/HanYiCuSongJian.ttf
Normal file
Binary file not shown.
BIN
WpfAppTest/Fonts/SJQY.ttf
Normal file
BIN
WpfAppTest/Fonts/SJQY.ttf
Normal file
Binary file not shown.
86
WpfAppTest/MainViewModel.cs
Normal file
86
WpfAppTest/MainViewModel.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace WpfAppTest
|
||||
{
|
||||
public partial class MainViewModel : ObservableValidator
|
||||
{
|
||||
[ObservableProperty]
|
||||
public partial string SampleText { get; set; }
|
||||
public MainViewModel()
|
||||
{
|
||||
SampleText = "TDC(1);800X800;\r\nYJ500x500;\r\nT7C25;B7C25;\r\nG10C20;\r\nA12@100/200(6);\r\n62.24;";
|
||||
}
|
||||
[ObservableProperty]
|
||||
[NotifyDataErrorInfo]
|
||||
[MinLength(1)]
|
||||
private double pileSpacing;
|
||||
|
||||
public object SelectedItem { get; set; }
|
||||
public List<Student> Students { get; } = new List<Student>
|
||||
{
|
||||
new Student("Alice", 20),
|
||||
new Student("Bob", 22),
|
||||
new Student("Charlie", 19),
|
||||
new Student("Diana", 21),
|
||||
new Student("Ethan", 23)
|
||||
};
|
||||
public List<Gender> Genders { get; set; } = new List<Gender> { Gender.Male, Gender.Female };
|
||||
|
||||
public List<string> Items { get; } = new List<string>
|
||||
{
|
||||
"Item 1",
|
||||
"Item 2",
|
||||
"Item 3",
|
||||
"Item 4",
|
||||
"Item 5"
|
||||
};
|
||||
|
||||
[RelayCommand]
|
||||
private void Confirm()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
public enum Gender
|
||||
{
|
||||
Male,
|
||||
Female,
|
||||
}
|
||||
public class Student
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Age { get; set; }
|
||||
public int Birth { get; set; }
|
||||
|
||||
public int Month { get; set; }
|
||||
|
||||
public int Year { get; set; }
|
||||
|
||||
public int Day { get; set; }
|
||||
|
||||
public int MonthDay { get; set; }
|
||||
|
||||
public bool IsSelected { get; set; }
|
||||
|
||||
public Gender Gender { get; set; }
|
||||
|
||||
|
||||
public Student() { }
|
||||
public Student(string name, int age)
|
||||
{
|
||||
Name = name;
|
||||
Age = age;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Name}, {Age} years old";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
1224
WpfAppTest/ModernStyles.xaml
Normal file
1224
WpfAppTest/ModernStyles.xaml
Normal file
File diff suppressed because it is too large
Load Diff
139
WpfAppTest/ModernWindow.xaml
Normal file
139
WpfAppTest/ModernWindow.xaml
Normal file
@@ -0,0 +1,139 @@
|
||||
<local:ModernWindow
|
||||
x:Class="WpfAppTest.ModernWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:ModernWpf.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:wpfapptest="clr-namespace:WpfAppTest"
|
||||
Title="ModernWindow"
|
||||
Width="800"
|
||||
Height="450"
|
||||
d:DataContext="{d:DesignInstance Type=wpfapptest:MainViewModel}"
|
||||
d:Height="800"
|
||||
Icon="{StaticResource Logo}"
|
||||
Style="{StaticResource ModernWindowStyle}"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ObjectDataProvider
|
||||
x:Key="GenderEnumData"
|
||||
MethodName="GetValues"
|
||||
ObjectType="{x:Type sys:Enum}">
|
||||
<ObjectDataProvider.MethodParameters>
|
||||
<x:Type TypeName="wpfapptest:Gender" />
|
||||
</ObjectDataProvider.MethodParameters>
|
||||
</ObjectDataProvider>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
<ScrollViewer>
|
||||
<StackPanel Margin="20">
|
||||
<!-- 5. TextBox -->
|
||||
<TextBox Margin="0,0,0,15" local:ElementHelper.Watermark="请输入您的用户名">
|
||||
<local:ElementHelper.Prefix>
|
||||
<Path Data="{StaticResource IconUser}" Stroke="{StaticResource LightTextBrush}" />
|
||||
</local:ElementHelper.Prefix>
|
||||
</TextBox>
|
||||
|
||||
<local:ModernPasswordBox Margin="0,0,0,15" local:ElementHelper.Watermark="请输入密码">
|
||||
<local:ElementHelper.Prefix>
|
||||
<Path Data="{StaticResource IconLock}" Stroke="{StaticResource LightTextBrush}" />
|
||||
</local:ElementHelper.Prefix>
|
||||
</local:ModernPasswordBox>
|
||||
|
||||
<!-- 2. ComboBox (Searchable) -->
|
||||
<local:SearchableComboBox
|
||||
Margin="0,0,0,15"
|
||||
local:ElementHelper.Watermark="搜索..."
|
||||
IsEditable="True"
|
||||
ItemsSource="{Binding Items}"
|
||||
SelectedItem="{Binding SelectedItem}" />
|
||||
|
||||
<!-- 8. GroupBox with 6. CheckBox & 7. RadioButton -->
|
||||
<GroupBox Margin="0,0,0,15" Header="设置选项">
|
||||
<StackPanel Margin="5">
|
||||
<CheckBox
|
||||
Margin="0,5"
|
||||
Content="记住我"
|
||||
IsChecked="True" />
|
||||
<CheckBox Margin="0,5" Content="自动登录" />
|
||||
<Separator Margin="0,10" />
|
||||
<RadioButton
|
||||
Margin="0,5"
|
||||
Content="普通用户"
|
||||
GroupName="Role"
|
||||
IsChecked="True" />
|
||||
<RadioButton
|
||||
Margin="0,5"
|
||||
Content="管理员"
|
||||
GroupName="Role" />
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 4. Button with Icon -->
|
||||
<Button
|
||||
HorizontalAlignment="Left"
|
||||
local:ElementHelper.Icon="M12,4L12,20M4,12L20,12"
|
||||
Command="{Binding ConfirmCommand}"
|
||||
Content="登 录" />
|
||||
<DataGrid Margin="5" ItemsSource="{Binding Students}">
|
||||
<DataGrid.Columns>
|
||||
<DataGridCheckBoxColumn Binding="{Binding IsSelected}" Header="选择" />
|
||||
<DataGridTextColumn Binding="{Binding Name}" Header="姓名" />
|
||||
<DataGridTextColumn Binding="{Binding Age}" Header="年龄" />
|
||||
<DataGridComboBoxColumn
|
||||
Header="性别"
|
||||
ItemsSource="{Binding Genders}"
|
||||
SelectedItemBinding="{Binding Gender}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<DataGrid ColumnWidth="*" ItemsSource="{Binding Students}">
|
||||
<DataGrid.Columns>
|
||||
|
||||
<!-- 1. 文本列:【必须】加上 EditingElementStyle -->
|
||||
<DataGridTextColumn
|
||||
Width="150"
|
||||
Binding="{Binding Name}"
|
||||
EditingElementStyle="{StaticResource ModernEditingTextBoxStyle}"
|
||||
Header="姓名" />
|
||||
|
||||
<DataGridTextColumn
|
||||
Width="80"
|
||||
Binding="{Binding Age}"
|
||||
EditingElementStyle="{StaticResource ModernEditingTextBoxStyle}"
|
||||
Header="年龄" />
|
||||
|
||||
<!-- 2. 复选框列:(TemplateColumn 不需要 EditingElementStyle,因为它直接包含 CheckBox) -->
|
||||
<DataGridTemplateColumn
|
||||
Width="80"
|
||||
Header="已选"
|
||||
SortMemberPath="IsSelected">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
<!-- 3. 下拉框列:【必须】加上 EditingElementStyle -->
|
||||
<DataGridComboBoxColumn
|
||||
Width="120"
|
||||
EditingElementStyle="{StaticResource ModernEditingComboBoxStyle}"
|
||||
Header="性别"
|
||||
ItemsSource="{Binding Source={StaticResource GenderEnumData}}"
|
||||
SelectedItemBinding="{Binding Gender}">
|
||||
<!-- 非编辑状态下的外观优化 -->
|
||||
|
||||
</DataGridComboBoxColumn>
|
||||
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<wpfapptest:RebarTextBlock RebarText="{Binding SampleText, Mode=TwoWay}" />
|
||||
<!--<TextBlock FontFamily="{StaticResource SJQY}" Text="CCCC" />-->
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</local:ModernWindow>
|
||||
29
WpfAppTest/ModernWindow.xaml.cs
Normal file
29
WpfAppTest/ModernWindow.xaml.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace WpfAppTest
|
||||
{
|
||||
/// <summary>
|
||||
/// ModernWindow.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ModernWindow
|
||||
{
|
||||
public ModernWindow()
|
||||
{
|
||||
DataContext = new MainViewModel();
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
24
WpfAppTest/NullToBooleanConverter.cs
Normal file
24
WpfAppTest/NullToBooleanConverter.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace WpfAppTest.Converter
|
||||
{
|
||||
public class NullToBooleanConverter : IValueConverter
|
||||
{
|
||||
public static readonly NullToBooleanConverter Instance = new NullToBooleanConverter();
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value != null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
36
WpfAppTest/NullableToVisibilityConverter.cs
Normal file
36
WpfAppTest/NullableToVisibilityConverter.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System;
|
||||
|
||||
namespace WpfAppTest.Converter
|
||||
{
|
||||
public class NullableToVisibilityConverter : IValueConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// The visibility value if the argument is null.
|
||||
/// </summary>
|
||||
public Visibility NullValue { get; set; }
|
||||
|
||||
public Visibility NotNullValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="NotNullToVisibilityConverter" />.
|
||||
/// </summary>
|
||||
public NullableToVisibilityConverter()
|
||||
{
|
||||
NullValue = Visibility.Collapsed;
|
||||
NotNullValue = Visibility.Visible;
|
||||
}
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value == null ? NullValue : NotNullValue;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return Binding.DoNothing;
|
||||
}
|
||||
}
|
||||
}
|
||||
71
WpfAppTest/PasswordBoxHelper.cs
Normal file
71
WpfAppTest/PasswordBoxHelper.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace WpfAppTest.Controls // 根据您的项目命名空间修改
|
||||
{
|
||||
public static class PasswordBoxHelper
|
||||
{
|
||||
public static readonly DependencyProperty HasPasswordProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"HasPassword",
|
||||
typeof(bool),
|
||||
typeof(PasswordBoxHelper),
|
||||
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
||||
|
||||
public static bool GetHasPassword(DependencyObject dp)
|
||||
{
|
||||
return (bool)dp.GetValue(HasPasswordProperty);
|
||||
}
|
||||
|
||||
public static void SetHasPassword(DependencyObject dp, bool value)
|
||||
{
|
||||
dp.SetValue(HasPasswordProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MonitorPasswordProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"MonitorPassword",
|
||||
typeof(bool),
|
||||
typeof(PasswordBoxHelper),
|
||||
new UIPropertyMetadata(false, OnMonitorPasswordChanged));
|
||||
|
||||
public static bool GetMonitorPassword(DependencyObject dp)
|
||||
{
|
||||
return (bool)dp.GetValue(MonitorPasswordProperty);
|
||||
}
|
||||
|
||||
public static void SetMonitorPassword(DependencyObject dp, bool value)
|
||||
{
|
||||
dp.SetValue(MonitorPasswordProperty, value);
|
||||
}
|
||||
|
||||
private static void OnMonitorPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is PasswordBox passwordBox)
|
||||
{
|
||||
if ((bool)e.NewValue)
|
||||
{
|
||||
passwordBox.PasswordChanged += PasswordBox_PasswordChanged;
|
||||
UpdateHasPassword(passwordBox); // Initial check
|
||||
}
|
||||
else
|
||||
{
|
||||
passwordBox.PasswordChanged -= PasswordBox_PasswordChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is PasswordBox passwordBox)
|
||||
{
|
||||
UpdateHasPassword(passwordBox);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateHasPassword(PasswordBox passwordBox)
|
||||
{
|
||||
SetHasPassword(passwordBox, passwordBox.Password.Length > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
WpfAppTest/Properties/AssemblyInfo.cs
Normal file
52
WpfAppTest/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("WpfAppTest")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("WpfAppTest")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2025")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 会使此程序集中的类型
|
||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//若要开始生成可本地化的应用程序,请设置
|
||||
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
|
||||
//在 <PropertyGroup> 中。例如,如果你使用的是美国英语。
|
||||
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
|
||||
//对以下 NeutralResourceLanguage 特性的注释。 更新
|
||||
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
|
||||
//(未在页面中找到资源时使用,
|
||||
//或应用程序资源字典中找到时使用)
|
||||
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
|
||||
//(未在页面中找到资源时使用,
|
||||
//、应用程序或任何主题专用资源字典中找到时使用)
|
||||
)]
|
||||
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
71
WpfAppTest/Properties/Resources.Designer.cs
generated
Normal file
71
WpfAppTest/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本: 4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能导致不正确的行为,如果
|
||||
// 重新生成代码,则所做更改将丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace WpfAppTest.Properties
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 强类型资源类,用于查找本地化字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources
|
||||
{
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WpfAppTest.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重写当前线程的 CurrentUICulture 属性,对
|
||||
/// 使用此强类型资源类的所有资源查找执行重写。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
return resourceCulture;
|
||||
}
|
||||
set
|
||||
{
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
WpfAppTest/Properties/Resources.resx
Normal file
117
WpfAppTest/Properties/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
30
WpfAppTest/Properties/Settings.Designer.cs
generated
Normal file
30
WpfAppTest/Properties/Settings.Designer.cs
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace WpfAppTest.Properties
|
||||
{
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
WpfAppTest/Properties/Settings.settings
Normal file
7
WpfAppTest/Properties/Settings.settings
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
81
WpfAppTest/RebarTextBlock.cs
Normal file
81
WpfAppTest/RebarTextBlock.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace WpfAppTest
|
||||
{
|
||||
internal class RebarTextBlock : TextBlock
|
||||
{
|
||||
public static readonly DependencyProperty RebarTextProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(RebarText),
|
||||
typeof(string),
|
||||
typeof(WpfAppTest.RebarTextBlock),
|
||||
new PropertyMetadata(string.Empty, OnRebarTextChanged));
|
||||
|
||||
public string RebarText
|
||||
{
|
||||
get => (string)GetValue(RebarTextProperty);
|
||||
set => SetValue(RebarTextProperty, value);
|
||||
}
|
||||
|
||||
private static void OnRebarTextChanged(
|
||||
DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
((WpfAppTest.RebarTextBlock)d).BuildInlines(e.NewValue as string);
|
||||
}
|
||||
//{Assembly.GetExecutingAssembly().GetName()}
|
||||
internal static readonly FontFamily RebarFont = new($"pack://application:,,,/WpfAppTest;component/Fonts/#SJQY");
|
||||
internal static readonly FontFamily NormalFont = new($"pack://application:,,,/WpfAppTest;component/Fonts/#汉仪粗宋简");
|
||||
private void BuildInlines(string text)
|
||||
{
|
||||
var sjqy = (FontFamily)Application.Current.Resources["SJQY"];
|
||||
Inlines.Clear();
|
||||
if (string.IsNullOrEmpty(text)) return;
|
||||
var regex = new Regex(
|
||||
@"(?<![A-Za-z])([ABCD])(?=\s*(?:[ØΦ]\d|\d+@\d+))",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
int lastIndex = 0;
|
||||
|
||||
foreach (Match match in regex.Matches(text))
|
||||
{
|
||||
// 普通文本
|
||||
if (match.Index > lastIndex)
|
||||
{
|
||||
this.Inlines.Add(new Run
|
||||
{
|
||||
Text = text.Substring(lastIndex, match.Index - lastIndex),
|
||||
FontFamily = NormalFont
|
||||
});
|
||||
}
|
||||
|
||||
// 钢筋等级(SJQY)
|
||||
this.Inlines.Add(new Run
|
||||
{
|
||||
Text = match.Value,
|
||||
FontFamily = sjqy
|
||||
});
|
||||
|
||||
lastIndex = match.Index + match.Length;
|
||||
}
|
||||
|
||||
// 尾部普通文本
|
||||
if (lastIndex < text.Length)
|
||||
{
|
||||
this.Inlines.Add(new Run
|
||||
{
|
||||
Text = text.Substring(lastIndex),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
WpfAppTest/UnitConverter.cs
Normal file
56
WpfAppTest/UnitConverter.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace WpfAppTest
|
||||
{
|
||||
internal class UnitConverter : IValueConverter
|
||||
{
|
||||
private string DefaultUnit { get; set; } = "mm";
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
if (value is double d)
|
||||
{
|
||||
string unit = parameter as string ?? DefaultUnit;
|
||||
// 使用StringFormat时,value会先被格式化,这里直接拼接单位
|
||||
return $"{d.ToString(culture)} {unit}";
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is string str)
|
||||
{
|
||||
// 提取纯数字字符串(允许中间态如 '1.', '-.')
|
||||
str = str.Trim();
|
||||
|
||||
var match = Regex.Match(str, @"[-+]?[0-9]*\.?[0-9]*");
|
||||
if (match.Success)
|
||||
{
|
||||
string numberPart = match.Value;
|
||||
|
||||
// 处理中间态输入,允许返回未完成的文本(让 UI 不抖动)
|
||||
if (string.IsNullOrEmpty(numberPart) || numberPart.EndsWith("-") || numberPart.EndsWith(".") || numberPart.EndsWith("-."))
|
||||
return DependencyProperty.UnsetValue;
|
||||
|
||||
if (double.TryParse(numberPart, NumberStyles.Any, culture, out double result))
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
132
WpfAppTest/WindowBehavior.cs
Normal file
132
WpfAppTest/WindowBehavior.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Interop;
|
||||
|
||||
namespace WpfAppTest.Behavior
|
||||
{
|
||||
public static class WindowBehavior
|
||||
{
|
||||
// 这是我们的附加属性,用于启用自定义窗口行为
|
||||
public static readonly DependencyProperty EnableCustomWindowBehaviorProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"EnableCustomWindowBehavior",
|
||||
typeof(bool),
|
||||
typeof(WindowBehavior),
|
||||
new PropertyMetadata(false, OnEnableCustomWindowBehaviorChanged));
|
||||
|
||||
public static bool GetEnableCustomWindowBehavior(DependencyObject obj)
|
||||
{
|
||||
return (bool)obj.GetValue(EnableCustomWindowBehaviorProperty);
|
||||
}
|
||||
|
||||
public static void SetEnableCustomWindowBehavior(DependencyObject obj, bool value)
|
||||
{
|
||||
obj.SetValue(EnableCustomWindowBehaviorProperty, value);
|
||||
}
|
||||
|
||||
// 当 EnableCustomWindowBehavior 属性值改变时触发
|
||||
private static void OnEnableCustomWindowBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Window window)
|
||||
{
|
||||
if ((bool)e.NewValue)
|
||||
{
|
||||
// 当启用行为时,在窗口加载后查找并绑定元素
|
||||
window.Loaded += Window_Loaded;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 当禁用行为时,解除绑定(如果需要更彻底的清理,可以做更多操作)
|
||||
window.Loaded -= Window_Loaded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 窗口加载后执行,此时 ControlTemplate 已经被应用
|
||||
private static void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Window window)
|
||||
{
|
||||
// *** 关键:通过 FindName 在 ControlTemplate 中查找元素 ***
|
||||
// 这些元素的 x:Name 必须与你的 Window 样式模板中的名称一致!
|
||||
Button minimizeButton = window.Template.FindName("MinimizeButton", window) as Button;
|
||||
Button maximizeRestoreButton = window.Template.FindName("MaximizeRestoreButton", window) as Button;
|
||||
Button closeButton = window.Template.FindName("CloseButton", window) as Button;
|
||||
Border titleBarDragArea = window.Template.FindName("WindowBorder", window) as Border; // 或者你的标题栏 Border 的 x:Name
|
||||
Border resizeGrip = window.Template.FindName("PART_ResizeGrip", window) as Border; // 调整大小手柄
|
||||
|
||||
// --- 绑定按钮点击事件 ---
|
||||
if (minimizeButton != null)
|
||||
{
|
||||
minimizeButton.Click += (s, ev) => window.WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
if (maximizeRestoreButton != null)
|
||||
{
|
||||
maximizeRestoreButton.Click += (s, ev) =>
|
||||
{
|
||||
if (window.WindowState == WindowState.Normal)
|
||||
window.WindowState = WindowState.Maximized;
|
||||
else
|
||||
window.WindowState = WindowState.Normal;
|
||||
};
|
||||
}
|
||||
|
||||
if (closeButton != null)
|
||||
{
|
||||
closeButton.Click += (s, ev) => window.Close();
|
||||
}
|
||||
|
||||
// --- 绑定标题栏拖拽和双击最大化事件 ---
|
||||
if (titleBarDragArea != null)
|
||||
{
|
||||
// 单击并拖动以移动窗口
|
||||
titleBarDragArea.MouseLeftButtonDown += (s, ev) =>
|
||||
{
|
||||
if (ev.ClickCount == 1 && window.WindowState == WindowState.Normal)
|
||||
{
|
||||
window.DragMove(); // WPF 内置的拖动方法
|
||||
}
|
||||
};
|
||||
|
||||
// 双击标题栏最大化/还原窗口
|
||||
titleBarDragArea.MouseLeftButtonDown += (s, ev) =>
|
||||
{
|
||||
if (ev.ClickCount == 2)
|
||||
{
|
||||
if (window.WindowState == WindowState.Normal)
|
||||
window.WindowState = WindowState.Maximized;
|
||||
else
|
||||
window.WindowState = WindowState.Normal;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// --- 处理调整大小手柄 ---
|
||||
if (resizeGrip != null)
|
||||
{
|
||||
resizeGrip.PreviewMouseLeftButtonDown += (s, ev) =>
|
||||
{
|
||||
if (window.WindowState == WindowState.Normal)
|
||||
{
|
||||
// 调用 Win32 API 来启动窗口调整大小
|
||||
IntPtr handle = new WindowInteropHelper(window).Handle;
|
||||
SendMessage(handle, 0x0112, (IntPtr)0xF008, IntPtr.Zero); // WM_SYSCOMMAND, SC_SIZE (bottom-right)
|
||||
ev.Handled = true; // 阻止事件冒泡,避免与窗口拖动冲突
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- P/Invoke: 调用 Windows API 的 SendMessage 函数 ---
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||
}
|
||||
}
|
||||
29
WpfAppTest/WpfAppTest.csproj
Normal file
29
WpfAppTest/WpfAppTest.csproj
Normal file
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<UseWPF>true</UseWPF>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
|
||||
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
|
||||
<PackageReference Include="System.Buffers" Version="4.6.0" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.6.0" />
|
||||
<PackageReference Include="System.Numerics.Vectors" Version="4.6.0" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.0" />
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Fonts\HanYiCuSongJian.ttf" />
|
||||
<Resource Include="Fonts\SJQY.ttf" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user