Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在WPF中将回调接口用作DependencyProperty?_Wpf_Xaml_C# 4.0_Mvvm_Dependency Properties - Fatal编程技术网

在WPF中将回调接口用作DependencyProperty?

在WPF中将回调接口用作DependencyProperty?,wpf,xaml,c#-4.0,mvvm,dependency-properties,Wpf,Xaml,C# 4.0,Mvvm,Dependency Properties,很抱歉,我的问题很长,但我觉得有必要包括所有这些信息 到目前为止,我一直在使用一种可能非正统的方式将UserControl添加到我的应用程序中。假设我有一个名为Diagnostics的用户控件,它有一个按钮,单击该按钮时,执行特定于拥有它的应用程序的功能。例如,如果我将诊断放入AppA,我希望它显示“A”,如果我将其放入AppB,我希望AppB定义行为,使其显示“B” 我通常通过一个回调接口来实现这一点,该接口被传递给UserControl的构造函数,这非常简单。下面是一些可能不会编译的示例“代

很抱歉,我的问题很长,但我觉得有必要包括所有这些信息

到目前为止,我一直在使用一种可能非正统的方式将UserControl添加到我的应用程序中。假设我有一个名为
Diagnostics
的用户控件,它有一个按钮,单击该按钮时,执行特定于拥有它的应用程序的功能。例如,如果我将诊断放入AppA,我希望它显示“A”,如果我将其放入AppB,我希望AppB定义行为,使其显示“B”

我通常通过一个回调接口来实现这一点,该接口被传递给UserControl的构造函数,这非常简单。下面是一些可能不会编译的示例“代码”,但只是为了澄清我以前基本上做了什么,以及我正在尝试做什么:

public interface IDiagnosticsCallback {
    void DisplayDiagnostics(); // implemented by owner of Diagnostics UserControl
}

public class MyApp : IDiagnosticsCallback {
    public void DisplayDiagnostics() {
        MessageBox.Show("Diagnostics displayed specifically for MyApp here");
    }
}

public Diagnostics : UserControl {
    private IDiagnosticsCallback _callback { get; private set; }

    public Diagnostics(IDiagnosticsCallback callback) {
        _callback = callback;
    }

    public void ShowDiagnostics_Click(object sender, EventArgs e) {
        _callback.DisplayDiagnostics();
    }
}
我过去遇到的问题是理解如何在XAML中声明一个UserControl,该UserControl在其构造函数中接受一个参数(即没有默认构造函数),显然您不能。我使用了一种相当不雅观的方法来解决这个问题——我将用XAML给主面板命名,然后从代码隐藏中创建诊断,将必要的回调传递给它,然后将诊断添加到面板的子列表中。Gross和违反了MVVM的使用,但它可以工作

这个周末,我决定尝试学习如何为一个类和一个文本框创建一个
dependencProperty
,并使用数据绑定。它看起来像这样:

public ClassA
{
    public void ShowSomethingSpecial()
    {
        MessageBox.Show("Watch me dance!");
    }
}

public MyApp
{
    public ClassA Foo { get; set; }
}

public Diagnostics : UserControl
{
    public static readonly DependencyProperty SomethingProperty = DependencyProperty.Register("Something", typeof(ClassA), typeof(Diagnostics), new PropertyMetadata());

    public ClassA Something
    {
        get { return (MyApp)GetValue(SomethingProperty); }
        set { SetValue(SomethingProperty, value); }
    }

    // now uses default constructor

    public void ShowSomethingSpecial_Click(object sender, EventArgs e)
    {
        Something.ShowSomethingSpecial();
    }
}


MyApp.xaml
<diags:Diagnostics Something="{Binding Foo}" />
public Diagnostics : UserControl
{
    public interface IDioCallback
    {
        short ReadInputs();
        short ReadOutputs();
        void SetOutput( char bit);
    }

    public IDioCallback DioCallbackInterface {
        get { return (IDioCallback)GetValue(DioCallbackInterfaceProperty); }
        set { SetValue(DioCallbackInterfaceProperty,value); }
    }

    // Using a DependencyProperty as the backing store for DioCallbackInterface.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DioCallbackInterfaceProperty = DependencyProperty.Register("DioCallbackInterface",typeof(IDioCallback),typeof(Diagnostics),new PropertyMetadata(0)); // PropertyMetadata is the problem...
}

public class DIO : IDioCallback
{
    public short ReadInputs() { return 0; }
    public short ReadOutputs() { return 0; }
    public void SetOutput( char bit) {}
}

public class MyApp 
{
    public DIO MyDIO { get; set; }
}

MyApp.xaml
<diags:Diagnostics DioCallbackInterface="{Binding MyDIO}" />
public ClassA
{
公共空间展示一些特别的东西()
{
MessageBox.Show(“看我跳舞!”);
}
}
公共MyApp
{
公共类A Foo{get;set;}
}
公共诊断:用户控制
{
public static readonly dependencProperty SomethingProperty=dependencProperty.Register(“Something”、typeof(ClassA)、typeof(Diagnostics)、new PropertyMetadata());
A类什么的
{
get{return(MyApp)GetValue(SomethingProperty);}
set{SetValue(SomethingProperty,value);}
}
//现在使用默认构造函数
public void ShowSomethingSpecial_单击(对象发送者,事件参数e)
{
show somethingspecial();
}
}
MyApp.xaml
所以Foo是MyApp的一个属性,它被数据绑定到诊断的Something dependencProperty。当我单击UserControl中的按钮时,行为由ClassA定义。更好,可以与MVVM一起使用

我现在想做的是更进一步,而是将回调接口传递给我的UserControl,以便它可以获取我的数字输入和输出的状态。我在找这样的东西:

public ClassA
{
    public void ShowSomethingSpecial()
    {
        MessageBox.Show("Watch me dance!");
    }
}

public MyApp
{
    public ClassA Foo { get; set; }
}

public Diagnostics : UserControl
{
    public static readonly DependencyProperty SomethingProperty = DependencyProperty.Register("Something", typeof(ClassA), typeof(Diagnostics), new PropertyMetadata());

    public ClassA Something
    {
        get { return (MyApp)GetValue(SomethingProperty); }
        set { SetValue(SomethingProperty, value); }
    }

    // now uses default constructor

    public void ShowSomethingSpecial_Click(object sender, EventArgs e)
    {
        Something.ShowSomethingSpecial();
    }
}


MyApp.xaml
<diags:Diagnostics Something="{Binding Foo}" />
public Diagnostics : UserControl
{
    public interface IDioCallback
    {
        short ReadInputs();
        short ReadOutputs();
        void SetOutput( char bit);
    }

    public IDioCallback DioCallbackInterface {
        get { return (IDioCallback)GetValue(DioCallbackInterfaceProperty); }
        set { SetValue(DioCallbackInterfaceProperty,value); }
    }

    // Using a DependencyProperty as the backing store for DioCallbackInterface.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DioCallbackInterfaceProperty = DependencyProperty.Register("DioCallbackInterface",typeof(IDioCallback),typeof(Diagnostics),new PropertyMetadata(0)); // PropertyMetadata is the problem...
}

public class DIO : IDioCallback
{
    public short ReadInputs() { return 0; }
    public short ReadOutputs() { return 0; }
    public void SetOutput( char bit) {}
}

public class MyApp 
{
    public DIO MyDIO { get; set; }
}

MyApp.xaml
<diags:Diagnostics DioCallbackInterface="{Binding MyDIO}" />
公共诊断:用户控制 { 公共接口回调 { 短读输入(); 短读输出(); 无效设置输出(字符位); } 公共回调回调回调接口{ 获取{return(IDioCallback)GetValue(DioCallbackInterfaceProperty);} set{SetValue(DioCallbackInterfaceProperty,value);} } //使用DependencyProperty作为DioCallbackInterface的后台存储。这将启用动画、样式、绑定等。。。 公共静态只读DependencyProperty DioCallbackInterfaceProperty=DependencyProperty.Register(“DioCallbackInterface”、typeof(IDioCallback)、typeof(Diagnostics)、new PropertyMetadata(0));//PropertyMetadata是问题所在。。。 } 公共类DIO:回调 { public short ReadInputs(){return 0;} public short ReadOutputs(){return 0;} public void SetOutput(字符位){} } 公共类MyApp { 公共DIO MyDIO{get;set;} } MyApp.xaml 虽然我的代码(可能不是上面的代码,但我真正的项目)编译成功,但似乎传递给Register的PropertyMetadata有问题。我得到一个异常,它说“默认值类型与属性'DioCallbackInterface'的类型不匹配。”


我是在做一些非正统的事情,还是这种数据绑定接口的方法真的可行?如果不是,根据用户控件所使用的应用程序定义用户控件行为的推荐方法是什么?

您提到的例外情况如下:

new PropertyMetadata(0)
您已经传递了0(类型为Int32),而不是空值或接口所需的任何值:
IDioCallback

我不能说您选择的方式是错误的,但是您应该记住,UserControl的每个用户都必须实现您定义的接口。如果有多个属性要传递给用户控件,则基本上可以通过DependencyProperty丢弃它们

在本例中,您还希望向按钮注入一些逻辑。让我假设这个控件只有一个按钮
MVVM
-处理事件的方法是通过-您可以在
ViewModel
中声明command属性,并将其用作用户控件中数据绑定的数据源,作为DependencyProperty,将其正确传递到按钮

您还可以与所有数据上下文达成协议,并为该属性使用特殊名称。例如:

public interface IViewModelWithCommand
{
    public ICommand TheCommand { get; }
}
为您需要的每个数据上下文实现它,并在用户控件的数据模板中使用
命令
属性名。在代码隐藏中,您可以创建传递给用户控件的
DataContext
的类型验证,并在类型未实现接口时引发异常

以下是您可能会感兴趣的几篇文章:

使用RelayCommand将简化您的生活,因为您不需要为每个命令重新实现接口,相反,您需要