You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UWP中UserControl绑定ICommand:x:Bind正常,ElementName绑定报错

问题描述

使用x:Bind绑定自定义UserControl的SendInputCommand属性时一切正常,但将MainPage中的绑定代码替换为{Binding DataContext.SendInputCommand, ElementName=MyPage}后,在mainpage.xaml.cs的InitializeComponent方法中会抛出未处理异常。但同样的绑定方式用在Button的Command属性上却能正常运行,请问问题出在哪里?


复现代码

MyControl1.xaml.cs

public sealed partial class MyUserControl1 : UserControl
{
    public ICommand SendInputCommand
    {
        get { return (ICommand)GetValue(SendInputCommandProperty); }
        set { SetValue(SendInputCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SendInputCommandProperty =
        DependencyProperty.Register("MyProperty", typeof(ICommand), typeof(MyUserControl1), new PropertyMetadata(null));

    public MyUserControl1()
    {
        
        this.InitializeComponent();
    }
}

MyControl1.xaml

<UserControl
x:Class="TestBindingSolution.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestBindingSolution"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400"
x:Name="mycontrol1">

<Grid>
    <Button Content="ttt" Command="{x:Bind SendInputCommand}" />
</Grid>

MainPage.xaml

<Page
x:Class="TestBindingSolution.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestBindingSolution"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewmodels="using:TestBindingSolution.ViewModels" 
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
x:Name="MyPage"
Loaded="Page_Loaded">
<Page.DataContext>
    <viewmodels:MainPageViewModel x:Name="ViewModel"/>        
</Page.DataContext>

<StackPanel>
    <Button  Content="ssss" Command="{Binding DataContext.SendInputCommand,ElementName=MyPage}"/>
    <local:MyUserControl1 SendInputCommand="{x:Bind ViewModel.SendInputCommand}" />
</StackPanel>

MainPageViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using TestBindingSolution.Custom;

namespace TestBindingSolution.ViewModels
{
    public  class MainPageViewModel : Observable
    {
        #region Commands 
        public RelayCommand SendInputCommand { get; }
        #endregion
        public MainPageViewModel() 
        {
            this.SendInputCommand = new RelayCommand(this.OnSendInputCommand,this.CanExecuteSendInputCommand);
            
        }

        private bool CanExecuteSendInputCommand(object parameter)
        {
            return true;
        }

        private void OnSendInputCommand(object parameter)
        {
            throw new NotImplementedException();
        }
    }
}

补充代码(Observable和RelayCommand)

Observable类

public abstract class Observable : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual bool SetValue<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(storage, value))
            return false;

        storage = value;
        this.RaisePropertyChanged(propertyName);

        return true;
    }

    public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

RelayCommand类

public class RelayCommand : ICommand
{
    public event EventHandler CanExecuteChanged;

    private Action<object> _commandAction;
    private Func<object, bool> _canExecuteFunction;

    public RelayCommand(Action<object> commandAction)
        : this(commandAction, null)
    {
    }

    public RelayCommand(Action<object> commandAction, Func<object, bool> canExecuteFunction)
    {
        this._commandAction = commandAction;
        this._canExecuteFunction = canExecuteFunction;
    }

    public void RaiseCanExecuteChanged()
    {
        this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    public bool CanExecute(object parameter)
    {
        bool returnValue = true;
        if (this._canExecuteFunction != null)
        {
            returnValue = this._canExecuteFunction.Invoke(parameter);
        }
        return returnValue;
    }

    public void Execute(object parameter)
    {
        this._commandAction?.Invoke(parameter);
    }
}

问题根源

核心错误:你在注册依赖属性时,DependencyProperty.Register的第一个参数(依赖属性的唯一标识名称)填成了"MyProperty",但对应的CLR包装属性名是SendInputCommand,两者完全不匹配。

WPF/UWP的Binding系统依赖依赖属性的注册名称来匹配属性,而x:Bind是编译时绑定,直接访问CLR属性,所以不会暴露这个错误。Button的Command是系统内置的依赖属性,名称匹配正确,因此绑定能正常运行。


解决方法

修改SendInputCommandProperty的注册代码,将第一个参数改为与CLR属性一致的"SendInputCommand":

public static readonly DependencyProperty SendInputCommandProperty =
    DependencyProperty.Register("SendInputCommand", typeof(ICommand), typeof(MyUserControl1), new PropertyMetadata(null));

修改后,使用{Binding DataContext.SendInputCommand, ElementName=MyPage}绑定自定义UserControl的SendInputCommand属性即可正常工作。


内容的提问来源于stack exchange,提问作者Guru98

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 13:50:40