WPF C#UserControl DependencyProperty命令绑定为null
我创建了一个WPF C#UserControl DependencyProperty命令绑定为null,c#,wpf,xaml,viewmodel,commandbinding,C#,Wpf,Xaml,Viewmodel,Commandbinding,我创建了一个UserControl作为文件浏览工具,我想实现命令作为dependencProperties进行加载和保存,这样我就可以从视图模型绑定命令,以便处理它们 现在的问题是,如果我使用预定义的命令如打开或保存并在我的窗口中处理它们,它会起作用,但是如果我从我的视图模型使用绑定,这些命令是空的 下面的代码是一个示例程序,其中我删除了对我的问题不重要的所有内容,因为这可能是太多的代码 用户控制 XAML 代码隐藏 视图模型 使用System.ComponentModel; 使用Sys
UserControl
作为文件浏览工具,我想实现命令
作为dependencProperties
进行加载和保存,这样我就可以从视图模型
绑定命令
,以便处理它们
现在的问题是,如果我使用预定义的命令
如打开
或保存
并在我的窗口
中处理它们,它会起作用,但是如果我从我的视图模型
使用绑定
,这些命令
是空的
下面的代码是一个示例程序,其中我删除了对我的问题不重要的所有内容,因为这可能是太多的代码
用户控制 XAML
代码隐藏
视图模型
使用System.ComponentModel;
使用System.Runtime.CompilerServices;
使用System.Windows.Input;
使用Prism.命令;
命名空间WpfApplication1.Models
{
公共类UserControlViewModel
:inotifyproperty已更改
{
公共事件属性更改事件处理程序属性更改;
公共DelegateCommand ExecuteCommand{get;}
私有void ExecuteCommand_Executed(ICommand cmd)=>cmd?.Execute(“C:\\Test.txt”);
私有无效通知([CallerMemberName]字符串名称=null)
{
if(name!=null)
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(名称));
}
公共用户控制视图模型()
{
ExecuteCommand=新的DelegateCommand(ExecuteCommand_已执行);
}
}
}
窗口 XAML 视图模型
使用System.ComponentModel;
使用System.Runtime.CompilerServices;
使用System.Windows;
使用Prism.命令;
命名空间WpfApplication1.Models
{
公共类MainWindowViewModel:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
公共DelegateCommand OpenCommand{get;}
已执行私有void OpenCommand_(字符串文件)
{
Show($“Model:{file}”);
}
私有无效通知([CallerMemberName]字符串名称=null)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(名称));
}
公共主窗口视图模型()
{
OpenCommand=新的DelegateCommand(执行OpenCommand_);
}
}
}
该窗口包含一个预定义的
Open命令
,该命令以这种方式工作,但绑定
不起作用
为了运行这个应用程序,您需要Prism.Wpf NuGet包。看起来您在这里找到了一些奇怪的东西。但套用我一位朋友的话说,“好消息是,这次癌症更容易治疗” 首先,我使用PresentationTraceSources.TraceLevel对您的绑定进行了活检:
<local:TestControl
LoadCommand="{Binding
Source={StaticResource ViewModel},
Path=OpenCommand,
PresentationTraceSources.TraceLevel=High}"
/>
TestControl
有自己的资源和键ViewModel
,所以这就是查找的结果。该资源是一个UserControlViewModel
,它没有OpenCommand
属性,在这种情况下,它在MainWindow
中以相同的名称隐藏完全不同的资源
我不知道这个viewmodel资源方案是从哪里来的,但可以看出这是一个严重的错误。main窗口中的任何人都不必担心在TestControl
中内部使用了哪些资源键
幸运的是,没有必要制造这个问题。您可以删除一段代码,最终得到更简单、更健壮、更可维护的东西
因此,要解决问题:
首先,不要将所有ViewModel都创建为资源,因为没有理由这样做,这会导致问题。将此ExecuteCommand
绑定与您拥有的绑定进行比较。你从这些东西中得到了什么?没有什么。如果您费心设置DataContext
,请将其用作DataContext
最后,用户控件创建自己的视图模型通常是不好的做法,其原因现在已经非常明显了。我发现,当它们继承其父级的DataContext
时,混淆就少多了。但是我已经把你的设计抛到窗外一天了,所以我们就不谈了 感谢您的快速回答,但我更改了命令
,但没有任何帮助。同样,如果没有通过ViewModel
来“路由”命令,我无法添加一些自动行为,比如“真的覆盖了这个文件?”之类的东西。真正让我抓狂的是,如果我只是将我的UserControl
扔到窗口上,使用预定义的Open
命令,而不使用任何ViewModel
一切正常。。。但如果我想把一切都做好,添加一个ViewModel
并尝试将LoadCommand绑定到myViewModel
的命令中我可以在UserControl
后面的cody中看到dependencProperty
是空的。是的,我在myUserControl
上定义了dependencProperty
,在my上定义了DelegateCommand
ViewModel
。我的UserControl
上的一个功能就是能够稍后在XAML
级别的窗口中添加绑定
,并将命令绑定
传递到视图模型
中,我在其中声明了绑定,以便添加一些监视和默认行为,如“文件确实存在”仔细想想,我想我可能猜错了你保守秘密的一些密码。您是否正在设置DataContext=this代码>在你的用户控件中?您需要共享用户控件的完整代码,并显示viewmodel的来源。实际上是否有一个名为ViewModel
的StaticResource
?如果是这样,在哪里?@dukemadcat我无法从你现在的状态重建你的代码
<Window x:Class="WpfApplication1.MainWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:models="clr-namespace:WpfApplication1.Models"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200">
<Window.Resources>
<models:MainWindowViewModel x:Key="ViewModel"/>
</Window.Resources>
<Window.DataContext>
<Binding Source="{StaticResource ViewModel}"/>
</Window.DataContext>
<Window.CommandBindings>
<CommandBinding Command="Open" Executed="CommandBinding_Executed"/>
</Window.CommandBindings>
<StackPanel VerticalAlignment="Center">
<local:TestControl LoadCommand="{Binding Path=OpenCommand, Source={StaticResource ViewModel}}"/>
<local:TestControl LoadCommand="Open"/>
</StackPanel>
</Window>
<local:TestControl
LoadCommand="{Binding
Source={StaticResource ViewModel},
Path=OpenCommand,
PresentationTraceSources.TraceLevel=High}"
/>
System.Windows.Data Warning: 56 : Created BindingExpression (hash=34810426) for Binding (hash=11882558)
System.Windows.Data Warning: 58 : Path: 'OpenCommand'
System.Windows.Data Warning: 60 : BindingExpression (hash=34810426): Default mode resolved to OneWay
System.Windows.Data Warning: 61 : BindingExpression (hash=34810426): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=34810426): Attach to WpfApplication1.TestControl.LoadCommand (hash=5114324)
System.Windows.Data Warning: 67 : BindingExpression (hash=34810426): Resolving source
System.Windows.Data Warning: 70 : BindingExpression (hash=34810426): Found data context element: <null> (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=34810426): Activate with root item UserControlViewModel (hash=33108977)
System.Windows.Data Warning: 108 : BindingExpression (hash=34810426): At level 0 - for UserControlViewModel.OpenCommand found accessor <null>
System.Windows.Data Error: 40 : BindingExpression path error: 'OpenCommand' property not found on 'object' ''UserControlViewModel' (HashCode=33108977)'. BindingExpression:Path=OpenCommand; DataItem='UserControlViewModel' (HashCode=33108977); target element is 'TestControl' (Name=''); target property is 'LoadCommand' (type 'ICommand')
System.Windows.Data Warning: 80 : BindingExpression (hash=34810426): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 88 : BindingExpression (hash=34810426): TransferValue - using fallback/default value <null>
System.Windows.Data Warning: 89 : BindingExpression (hash=34810426): TransferValue - using final value <null>
public TestControl()
{
InitializeComponent();
var x = FindResource("ViewModel");
// Set breakpoint here and inspect x
;
}
<UserControl.DataContext>
<models:UserControlViewModel />
</UserControl.DataContext>
<Grid>
<Button Content="_Load" IsDefault="True"
Command="{Binding ExecuteCommand}"
CommandParameter="{Binding Path=LoadCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:TestControl}}}"/>
</Grid>
<Window.DataContext>
<models:MainWindowViewModel />
</Window.DataContext>
<StackPanel VerticalAlignment="Center">
<!--
local:TestControl.DataContext is its own viewmodel, so we use RelativeSource
to get to the Window, and then we look at Window.DataContext for the main window
viewmodel.
-->
<local:TestControl
LoadCommand="{Binding DataContext.OpenCommand, RelativeSource={RelativeSource AncestorType=Window}}"
/>
</StackPanel>