Windows Presentation Foundation或WPF是用于在基于Windows的应用程序中呈现用户界面的子系统。
`我需要有关 IPropertyChanged 的帮助,如何操作才能正常工作。 `C# 如何使用 IPropertyChanged 创建对象类? 我尝试在课堂上这样做,但它不起作用,我需要以某种方式查...
我有一个 DataGrid(称为 TheGrid),我想在其上实现复制和粘贴功能。复制功能很好用,但我不知道如何实现粘贴。我只需要得到...
如何在 Windows 8 / 2012 中左对齐窗口标题?
有没有办法(本质上)在 Windows 8 或 2012 机器中左对齐窗口标题? Window 8 或 2012 中的窗口标题水平居中对齐。 我们有一个 WPF 应用程序,它是...
我有自定义控件,内容模板中包含一些文本: 我有自定义控件,内容模板中包含一些文本: <ControlTemplate TargetType="{x:Type local:TouchScreenKey}"> <TextBlock><ContentPresenter Content="{TemplateBinding Title, Converter={StaticResource CaseConverter}}" /></TextBlock> </ControlTemplate> 和自定义 IValueConverter CaseConverter - 具有 UpperCase 属性。因此,当转换器的 UpperCase 属性设置为 true 时,它会在绑定时将文本转换为大写。如果我在标记中更改大写,一切都会顺利。但是,如果我在运行时更改属性 - 什么也不会发生 - 因为更改转换器属性不会强制我的控件重新绑定。 如何在转换器的属性更改时重新绑定使用转换器的控件? 据我所知,没有办法告诉转换器更新所有目标。转换器对目标一无所知。它只是一个无状态函数,F(x),接受一个值并返回另一个值。 要更新属性,您应该要求 WPF 这样做。例如,如果属性绑定到某个源属性,您可以实现 INotifyPropertyChanged,并触发 PropertyChanged 事件。或者您可以要求 BindingOperations 获取绑定表达式,并手动调用 UpdateTarget()。 也许转换器不是最好的选择?您可能还想考虑使用附加属性来更改大小写。 它可能对某人有帮助 - 我找到了解决方案 - 使用多重绑定 <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center"> <ContentPresenter> <ContentPresenter.Content> <MultiBinding Converter="{StaticResource MultiCaseConverter}"> <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Title" /> <Binding ElementName="TouchKeyboard" Path="UpperCase" /> </MultiBinding> </ContentPresenter.Content> </ContentPresenter> 并编写了 MultiCaseConverter - 根据第二个(大写)转换第一个参数
我有一个名为 GridContainer 的 UserControl,并在 XAML 中声明了一个 DataGrid 控件。我希望在窗口中使用时能够从 XAML 访问此 DataGrid: ...
当后台工作人员在 WPF 项目 (MVVM) 中工作时更新 UI
在我的WPF项目中,我需要将大量SQL数据传输到数据网格。自然是等的时间长了。我使用了MVVM模式。 为了使 UI 响应更快,我使用了后台工作者。但是屏幕
WPF MouseOver MenuItem 阻止焦点返回到窗口
我有一个带有自定义菜单和一些按钮的窗口。当用户将鼠标放在菜单项上时,我使菜单自动展开。每个按钮都有一个“鼠标悬停”...
使用 InvokeCommandAction 将额外参数传递给命令
有没有办法通过 Microsoft.Xaml.Behaviors.Wpf 中的 InvokeCommandAction 将额外参数(以及默认参数)传递给命令? 就像下面这样: 有没有办法通过 InvokeCommandAction 中的 Microsoft.Xaml.Behaviors.Wpf 将额外参数(与默认参数一起)传递给命令? 像下面这样: <behaviors:Interaction.Triggers> <behaviors:EventTrigger EventName="MouseDown"> <behaviors:InvokeCommandAction Command="{Binding Command, Mode=OneWay}" PassEventArgsToCommand="True" /> </behaviors:EventTrigger> </behaviors:Interaction.Triggers> 这里传递的参数是MouseButtonEventArgs: <behaviors:Interaction.Triggers> <behaviors:EventTrigger EventName="MouseDown"> <behaviors:InvokeCommandAction Command="{Binding Command, Mode=OneWay}" PassEventArgsToCommand="True"> <behaviors:InvokeCommandAction.CommandParameter> <MultiBinding Converter="{StaticResource ResourceKey=CommandConverter}"> <Binding ElementName="OtherElement" Mode="OneWay" /> </MultiBinding> </behaviors:InvokeCommandAction.CommandParameter> </behaviors:InvokeCommandAction> </behaviors:EventTrigger> </behaviors:Interaction.Triggers> 这里我想把 OtherElement 和 MouseButtonEventArgs 一起传递。有没有办法指定 MouseButtonEventArgs 参数? InvokeCommandAction 仅支持一个CommandParameter,即事件参数或绑定命令参数。如果您尝试同时执行这两项操作,命令参数将优先。由于 XAML 行为是开源的,您可以在 Github 上该类的 Invoke 方法中亲自查看它。 为了同时通过这两项,您必须编写自己的操作。如果您可以简单地创建 InvokeCommandAction 的派生类型并覆盖 Invoke,这将是一项简单的任务,但不幸的是它是 sealed。这意味着,您必须复制 InvokeCommandAction 的代码并进行调整。 首先,创建一个封装事件参数和命令参数的小类。 public class CompositeCommandParameter { public CompositeCommandParameter(EventArgs eventArgs, object parameter) { EventArgs = eventArgs; Parameter = parameter; } public EventArgs EventArgs { get; } public object Parameter { get; } } 接下来,从 GitHub 复制代码。本质上,您必须用自定义类型替换对 InvokeCommandAction 类型的显式引用,这里是 AdvancedInvokeCommandAction,当然还要调整 Invoke 方法,以便它创建一个 CompositeCommandParameter 实例并用它调用命令。 public sealed class AdvancedInvokeCommandAction : TriggerAction<DependencyObject> { private string commandName; public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(AdvancedInvokeCommandAction), null); public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(AdvancedInvokeCommandAction), null); public static readonly DependencyProperty EventArgsConverterProperty = DependencyProperty.Register("EventArgsConverter", typeof(IValueConverter), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null)); public static readonly DependencyProperty EventArgsConverterParameterProperty = DependencyProperty.Register("EventArgsConverterParameter", typeof(object), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null)); public static readonly DependencyProperty EventArgsParameterPathProperty = DependencyProperty.Register("EventArgsParameterPath", typeof(string), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null)); // ...other code. public object CommandParameter { get { return this.GetValue(AdvancedInvokeCommandAction.CommandParameterProperty); } set { this.SetValue(AdvancedInvokeCommandAction.CommandParameterProperty, value); } } // ...other code. protected override void Invoke(object parameter) { if (this.AssociatedObject != null) { ICommand command = this.ResolveCommand(); if (command != null) { object eventArgs = null; object commandParameter = this.CommandParameter; //if no CommandParameter has been provided, let's check the EventArgsParameterPath if (!string.IsNullOrWhiteSpace(this.EventArgsParameterPath)) { eventArgs = GetEventArgsPropertyPathValue(parameter); } //next let's see if an event args converter has been supplied if (eventArgs == null && this.EventArgsConverter != null) { eventArgs = this.EventArgsConverter.Convert(parameter, typeof(object), EventArgsConverterParameter, CultureInfo.CurrentCulture); } //last resort, let see if they want to force the event args to be passed as a parameter if (eventArgs == null && this.PassEventArgsToCommand) { eventArgs = parameter; } if (command.CanExecute(commandParameter)) { var compositeCommandParameter = new CompositeCommandParameter((EventArgs) eventArgs, commandParameter); command.Execute(compositeCommandParameter); } } } } // ...other code. } 在您的 XAML 代码中,您现在可以同时使用两者。由于您很可能仅将此操作与两个参数一起使用,因此您可以进一步自定义该操作以删除 PassEventArgsToCommand 参数。 <b:Interaction.Triggers> <b:EventTrigger EventName="MouseDown"> <local:AdvancedInvokeCommandAction Command="{Binding Command, Mode=OneWay}" PassEventArgsToCommand="True" CommandParameter="{Binding ElementName=OtherElement}" /> </b:EventTrigger> </b:Interaction.Triggers> 在您的视图模型中,该命令现在将获取类型为 CompositeCommandParameter 的对象。 这是 AdvancedInvokeCommandAction 的完整代码。 public sealed class AdvancedInvokeCommandAction : TriggerAction<DependencyObject> { private string commandName; public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(AdvancedInvokeCommandAction), null); public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(AdvancedInvokeCommandAction), null); public static readonly DependencyProperty EventArgsConverterProperty = DependencyProperty.Register("EventArgsConverter", typeof(IValueConverter), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null)); public static readonly DependencyProperty EventArgsConverterParameterProperty = DependencyProperty.Register("EventArgsConverterParameter", typeof(object), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null)); public static readonly DependencyProperty EventArgsParameterPathProperty = DependencyProperty.Register("EventArgsParameterPath", typeof(string), typeof(AdvancedInvokeCommandAction), new PropertyMetadata(null)); /// <summary> /// Gets or sets the name of the command this action should invoke. /// </summary> /// <value>The name of the command this action should invoke.</value> /// <remarks>This property will be superseded by the Command property if both are set.</remarks> public string CommandName { get { this.ReadPreamble(); return this.commandName; } set { if (this.CommandName != value) { this.WritePreamble(); this.commandName = value; this.WritePostscript(); } } } /// <summary> /// Gets or sets the command this action should invoke. This is a dependency property. /// </summary> /// <value>The command to execute.</value> /// <remarks>This property will take precedence over the CommandName property if both are set.</remarks> public ICommand Command { get { return (ICommand)this.GetValue(CommandProperty); } set { this.SetValue(CommandProperty, value); } } /// <summary> /// Gets or sets the command parameter. This is a dependency property. /// </summary> /// <value>The command parameter.</value> /// <remarks>This is the value passed to ICommand.CanExecute and ICommand.Execute.</remarks> public object CommandParameter { get { return this.GetValue(AdvancedInvokeCommandAction.CommandParameterProperty); } set { this.SetValue(AdvancedInvokeCommandAction.CommandParameterProperty, value); } } /// <summary> /// Gets or sets the IValueConverter that is used to convert the EventArgs passed to the Command as a parameter. /// </summary> /// <remarks>If the <see cref="Command"/> or <see cref="EventArgsParameterPath"/> properties are set, this property is ignored.</remarks> public IValueConverter EventArgsConverter { get { return (IValueConverter)GetValue(EventArgsConverterProperty); } set { SetValue(EventArgsConverterProperty, value); } } /// <summary> /// Gets or sets the parameter that is passed to the EventArgsConverter. /// </summary> public object EventArgsConverterParameter { get { return (object)GetValue(EventArgsConverterParameterProperty); } set { SetValue(EventArgsConverterParameterProperty, value); } } /// <summary> /// Gets or sets the parameter path used to extract a value from an <see cref= "EventArgs" /> property to pass to the Command as a parameter. /// </summary> /// <remarks>If the <see cref="Command"/> propert is set, this property is ignored.</remarks> public string EventArgsParameterPath { get { return (string)GetValue(EventArgsParameterPathProperty); } set { SetValue(EventArgsParameterPathProperty, value); } } /// <summary> /// Specifies whether the EventArgs of the event that triggered this action should be passed to the Command as a parameter. /// </summary> /// <remarks>If the <see cref="Command"/>, <see cref="EventArgsParameterPath"/>, or <see cref="EventArgsConverter"/> properties are set, this property is ignored.</remarks> public bool PassEventArgsToCommand { get; set; } /// <summary> /// Invokes the action. /// </summary> /// <param name="parameter">The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.</param> protected override void Invoke(object parameter) { if (this.AssociatedObject != null) { ICommand command = this.ResolveCommand(); if (command != null) { object eventArgs = null; object commandParameter = this.CommandParameter; //if no CommandParameter has been provided, let's check the EventArgsParameterPath if (!string.IsNullOrWhiteSpace(this.EventArgsParameterPath)) { eventArgs = GetEventArgsPropertyPathValue(parameter); } //next let's see if an event args converter has been supplied if (eventArgs == null && this.EventArgsConverter != null) { eventArgs = this.EventArgsConverter.Convert(parameter, typeof(object), EventArgsConverterParameter, CultureInfo.CurrentCulture); } //last resort, let see if they want to force the event args to be passed as a parameter if (eventArgs == null && this.PassEventArgsToCommand) { eventArgs = parameter; } if (command.CanExecute(commandParameter)) { var compositeCommandParameter = new CompositeCommandParameter((EventArgs) eventArgs, commandParameter); command.Execute(compositeCommandParameter); } } } } private object GetEventArgsPropertyPathValue(object parameter) { object commandParameter; object propertyValue = parameter; string[] propertyPathParts = EventArgsParameterPath.Split('.'); foreach (string propertyPathPart in propertyPathParts) { PropertyInfo propInfo = propertyValue.GetType().GetProperty(propertyPathPart); propertyValue = propInfo.GetValue(propertyValue, null); } commandParameter = propertyValue; return commandParameter; } private ICommand ResolveCommand() { ICommand command = null; if (this.Command != null) { command = this.Command; } else if (this.AssociatedObject != null) { // todo jekelly 06/09/08: we could potentially cache some or all of this information if needed, updating when AssociatedObject changes Type associatedObjectType = this.AssociatedObject.GetType(); PropertyInfo[] typeProperties = associatedObjectType.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo propertyInfo in typeProperties) { if (typeof(ICommand).IsAssignableFrom(propertyInfo.PropertyType)) { if (string.Equals(propertyInfo.Name, this.CommandName, StringComparison.Ordinal)) { command = (ICommand)propertyInfo.GetValue(this.AssociatedObject, null); } } } } return command; } } 您可以使用 EventArgsConverter 和 EventArgsConverterParameter 属性来创建一个简单的 IValueConverter,而不是发明自己的行为,它结合了原始事件参数和通常作为 CommandParameter 传递的对象: public class ContextualEventArgs : EventArgs { public object? Context { get; } public EventArgs OriginalEventArgs { get; } public ContextualEventArgs(EventArgs original, object? context) : base() { Context = context; OriginalEventArgs = original; } } public class ContextualEventArgsConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is EventArgs args) { return new ContextualEventArgs(args, parameter); } return Binding.DoNothing; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } 然后您可以将通常用作 CommandParameter 的任何内容放入 EventArgsConverterParameter 中。我在具有 ItemsControl.ItemTemplate 的 ComboBox 中使用它,将项目的 DataContext 添加到 SelectionChanged 事件参数: <!-- In Resources: <conv:ContextualEventArgsConverter x:Key="ContextualEventArgsConverter" /> --> <ComboBox ItemsSource="{Binding Source={StaticResource Modes}}" SelectedItem="{Binding Mode, Mode=OneWay}"> <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged"> <i:InvokeCommandAction Command="{Binding CmdItemModeSelectionChanged, Source={StaticResource CommandContainer}}" EventArgsConverter="{StaticResource ContextualEventArgsConverter}" EventArgsConverterParameter="{Binding .}" /> </i:EventTrigger> </i:Interaction.Triggers> </ComboBox> // In ctor: // CmdItemModeSelectionChanged = new DelegateCommand<ContextualEventArgs>(ExecuteItemModeSelectionChanged); private void ExecuteItemModeSelectionChanged(ContextualEventArgs args) { if (args.Context is MyItem item && args.OriginalEventArgs is SelectionChangedEventArgs sc) { if (sc.AddedItems.Count == 1 && sc.AddedItems[0] is Mode newMode && item.Mode != newMode) { ChangeItemMode(item, newMode); } } }
我遇到过一个奇怪的场景,框架拒绝刷新其内容。 我可以理解发生了什么,但我没有找到解决方案。 我有一个带有框架的页面(Fra...
我正在开发一个使用.Net5/WPF 显示WebView2 的应用程序。 我想禁用 CORS。 我已经安装了 Chromium Edge Canary 86.0.607.0。 在 Edge 中,可以通过添加以下参数来禁用 CORS...
PreviewTextInput 如果它是最后一个字符,则会删除小数点,但如果它位于中间,则不会删除小数点
我正在使用 PreviewTextInput 来验证十进制数。这是我的代码: 私人无效AmountTextBox_PreviewTextInput(对象发送者,System.Windows.Input.TextCompositionEventArgs e) { 文本框 t =
WPF - 适用于 XAML 的 MaterialDesign
我有两个单独的解决方案:解决方案 A 定义一个自定义 UserControl,如下所示: 我有两个单独的解决方案:解决方案 A 定义了一个自定义 UserControl,如您在此处看到的: <TextBox BorderBrush="{Binding ValueFG, RelativeSource={RelativeSource AncestorType=UserControl}}" Foreground="{Binding ValueFG, RelativeSource={RelativeSource AncestorType=UserControl}}" HorizontalAlignment="Right" md:HintAssist.HelperText="{Binding ValueHT, RelativeSource={RelativeSource AncestorType=UserControl}}" md:TextFieldAssist.LeadingIcon="{Binding ValueIcon, RelativeSource={RelativeSource AncestorType=UserControl}}" Text="{Binding ValueInput, RelativeSource={RelativeSource AncestorType=UserControl}, UpdateSourceTrigger=PropertyChanged}" Width="{Binding ValueWidth, RelativeSource={RelativeSource AncestorType=UserControl}}"/> public string ValueIcon { get { return (string)GetValue(ValueIconProperty); } set { SetValue(ValueIconProperty, value); } } public static readonly DependencyProperty ValueIconProperty = DependencyProperty.Register( nameof(ValueIcon), typeof(string), typeof(TxtInput), new PropertyMetadata("HumanGreeting")); 我遇到的唯一问题是 MaterialDesign 中的相应图标没有显示。 在解决方案 B 中,我添加了命名空间和对解决方案 A 的引用。然后我添加了这个自定义用户控件并尝试设置图标 fia 它对应的 Binding 属性。 <uc:TxtInput KeyText="Developer Name" DockPanelMargin="{Binding NameMargin}" ValueFG="{Binding NameFG}" ValueHT="{Binding NameHT}" ValueInput="{Binding Name}" ValueIcon="HumanGreetingVariant" Style="{StaticResource TxtInputLocal}"/> 不幸的是,图标根本没有添加。我还添加了第二个,没有明确的图标,以便应用默认图标 -> 我仍然没有显示图标。 运行时输出 在另一个项目中我已经使用了这些图标。我总是将它们设置为字符串,并且它按预期工作。 此外,如果我在同一解决方案中创建此 UserControl,它会按预期工作。 我可以自己解决: 在 Xaml 中,我必须添加以下属性: md:TextFieldAssist.HasLeadingIcon="True" 在代码隐藏中,我必须将属性更改为PackIconKind public PackIconKind ValueIcon { get { return (PackIconKind)GetValue(ValueIconProperty); } set { SetValue(ValueIconProperty, value); } } public static readonly DependencyProperty ValueIconProperty = DependencyProperty.Register( nameof(ValueIcon), typeof(PackIconKind), typeof(TxtInput), new PropertyMetadata(PackIconKind.HumanGreeting));
当我的应用程序中打开的选项卡太多而选项卡标题无法容纳在一行中时,TabItem 标题将分成两行。如果我固定 TabItem 宽度,这看起来真的很难看。 我想要...
我使用 webBrowser.navigate("some.pdf") 成功渲染了 pdf。是否可以禁用打印按钮和打印快捷键? 我尝试了 webBrowser.NavigateToString 但我
我正在尝试将本地化添加到我的 WPF Blazor 应用程序,但它不起作用。我用共享资源注入的 IStringLocalizer 总是返回默认的英语资源,即使我设置了不同的
我需要创建一个由文本框和按钮组成的新控件。我目前发现的最简洁的方法是使用像这样的 CusomControl: 继承自TextBox并添加功能...
Avalonia 的 TilePanel,`DependencyProperty` 到 `AvaloniaProperty`
我想要一个 Avalonia 的 WrapPanel,它通过将项目彼此相邻放置而包装其内容,没有间距,就像本文中一样:https://www.codeproject.com/Articles/482501/TilePanel-An-
我只是想知道是否可以创建一个WPF应用程序,允许用户使用特定的笔来绘制方向以形成特定的路径并能够显示路径数据。 这个想法是alm...
我想根据运行应用程序窗口的监视器的分辨率更改窗口的宽度和高度。 我使用此代码来获取监视器信息: var screen = Screen.FromHa...